├── .gitignore ├── README.md ├── app.js ├── config.sample ├── gtfs-realtime.proto.txt ├── nyct-subway.proto.txt └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/* 2 | /config.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mta-realtime-test 2 | Node app to consume and transform GTFS-realtime data from the New York City Subway. 3 | 4 | The MTA's GTFS-RT feed for the 1,2,3,4,5,6, and S trains resides at http://datamine.mta.info/mta_esi.php?key={YOURAPIKEY}&feed_id=1 5 | 6 | When you hit this endpoint, the response will be in protocol buffer format. This app uses the protobufjs node library to consume the raw data and convert it into a JSON object. 7 | 8 | The `/` endpoint returns the JSON for the `entities` feed, which includes `TripUpdate` and `VehiclePosition` messages 9 | 10 | Based on [yuningalexliu/mta-realtime](https://github.com/yuningalexliu/mta-realtime), but removed frontend parts and just made it a simple JSON endpoint. 11 | 12 | Read the MTA's [GTFS realtime specification document](http://datamine.mta.info/sites/all/files/pdfs/GTFS-Realtime-NYC-Subway%20version%201%20dated%207%20Sep.pdf) for more details on what you're looking at. 13 | 14 | The results look like this when prettified using the JSONview chrome plugin: 15 | ![localhost_3000](https://cloud.githubusercontent.com/assets/1833820/9156029/cfe53bbe-3e99-11e5-8b33-f29992d0119d.png) 16 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //based on https://github.com/yuningalexliu/mta-realtime, this app exposes the NYC GTFS-realtime 'entities' as JSON 2 | 3 | var express = require('express') 4 | var http = require('http') 5 | var ProtoBuf = require('protobufjs') 6 | var _ = require('underscore') 7 | 8 | var app = express() 9 | app.use(express.static(__dirname + '/public')); 10 | 11 | //options to be used in http request. See config.sample 12 | var options = require('./config').options 13 | 14 | 15 | var transit = ProtoBuf.loadProtoFile("nyct-subway.proto.txt").build("transit_realtime"); 16 | 17 | //process the response 18 | var processBuffers = function(response) { 19 | var data = []; 20 | response.on('data', function (chunk) { 21 | data.push(chunk); 22 | }); 23 | 24 | response.on('end', function () { 25 | data = Buffer.concat(data); 26 | var decodedFeedMessage = transit.FeedMessage.decode(data); 27 | tripData = decodedFeedMessage.entity; 28 | 29 | }); 30 | } 31 | 32 | var tripData; 33 | app.get('/', function(req, res) { 34 | http.request(options, processBuffers).end(function(){ 35 | res.json(tripData); 36 | }); 37 | 38 | }) 39 | 40 | //Run the server 41 | var server = app.listen(3000); -------------------------------------------------------------------------------- /config.sample: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | options: { 3 | host:'datamine.mta.info', 4 | path:'/mta_esi.php?key={YOURAPIKEY}&feed_id=1' 5 | } 6 | } -------------------------------------------------------------------------------- /gtfs-realtime.proto.txt: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc 2 | // 3 | // The content of this file is licensed under the Creative Commons Attribution 4 | // 3.0 License. 5 | // 6 | // Protocol definition file for GTFS-realtime. 7 | // 8 | // GTFS-realtime lets transit agencies provide consumers with realtime 9 | // information about disruptions to their service (stations closed, lines not 10 | // operating, important delays etc), location of their vehicles and expected 11 | // arrival times. 12 | // 13 | // This protocol is published at: 14 | // https://developers.google.com/transit/gtfs-realtime/ 15 | 16 | syntax = "proto2"; 17 | option java_package = "com.google.transit.realtime"; 18 | package transit_realtime; 19 | 20 | // The contents of a feed message. 21 | // A feed is a continuous stream of feed messages. Each message in the stream is 22 | // obtained as a response to an appropriate HTTP GET request. 23 | // A realtime feed is always defined with relation to an existing GTFS feed. 24 | // All the entity ids are resolved with respect to the GTFS feed. 25 | // 26 | // A feed depends on some external configuration: 27 | // - The corresponding GTFS feed. 28 | // - Feed application (updates, positions or alerts). A feed should contain only 29 | // items of one specified application; all the other entities will be ignored. 30 | // - Polling frequency 31 | message FeedMessage { 32 | 33 | // Metadata about this feed and feed message. 34 | required FeedHeader header = 1; 35 | 36 | // Contents of the feed. 37 | repeated FeedEntity entity = 2; 38 | 39 | // The extensions namespace allows 3rd-party developers to extend the 40 | // GTFS-realtime specification in order to add and evaluate new features and 41 | // modifications to the spec. 42 | extensions 1000 to 1999; 43 | } 44 | 45 | // Metadata about a feed, included in feed messages. 46 | message FeedHeader { 47 | // Version of the feed specification. 48 | // The current version is 1.0. 49 | required string gtfs_realtime_version = 1; 50 | 51 | // Determines whether the current fetch is incremental. Currently, 52 | // DIFFERENTIAL mode is unsupported and behavior is unspecified for feeds 53 | // that use this mode. There are discussions on the GTFS-realtime mailing 54 | // list around fully specifying the behavior of DIFFERENTIAL mode and the 55 | // documentation will be updated when those discussions are finalized. 56 | enum Incrementality { 57 | FULL_DATASET = 0; 58 | DIFFERENTIAL = 1; 59 | } 60 | optional Incrementality incrementality = 2 [default = FULL_DATASET]; 61 | 62 | // This timestamp identifies the moment when the content of this feed has been 63 | // created (in server time). In POSIX time (i.e., number of seconds since 64 | // January 1st 1970 00:00:00 UTC). 65 | optional uint64 timestamp = 3; 66 | 67 | // The extensions namespace allows 3rd-party developers to extend the 68 | // GTFS-realtime specification in order to add and evaluate new features and 69 | // modifications to the spec. 70 | extensions 1000 to 1999; 71 | } 72 | 73 | // A definition (or update) of an entity in the transit feed. 74 | message FeedEntity { 75 | // The ids are used only to provide incrementality support. The id should be 76 | // unique within a FeedMessage. Consequent FeedMessages may contain 77 | // FeedEntities with the same id. In case of a DIFFERENTIAL update the new 78 | // FeedEntity with some id will replace the old FeedEntity with the same id 79 | // (or delete it - see is_deleted below). 80 | // The actual GTFS entities (e.g. stations, routes, trips) referenced by the 81 | // feed must be specified by explicit selectors (see EntitySelector below for 82 | // more info). 83 | required string id = 1; 84 | 85 | // Whether this entity is to be deleted. Relevant only for incremental 86 | // fetches. 87 | optional bool is_deleted = 2 [default = false]; 88 | 89 | // Data about the entity itself. Exactly one of the following fields must be 90 | // present (unless the entity is being deleted). 91 | optional TripUpdate trip_update = 3; 92 | optional VehiclePosition vehicle = 4; 93 | optional Alert alert = 5; 94 | 95 | // The extensions namespace allows 3rd-party developers to extend the 96 | // GTFS-realtime specification in order to add and evaluate new features and 97 | // modifications to the spec. 98 | extensions 1000 to 1999; 99 | } 100 | 101 | // 102 | // Entities used in the feed. 103 | // 104 | 105 | // Realtime update of the progress of a vehicle along a trip. 106 | // Depending on the value of ScheduleRelationship, a TripUpdate can specify: 107 | // - A trip that proceeds along the schedule. 108 | // - A trip that proceeds along a route but has no fixed schedule. 109 | // - A trip that have been added or removed with regard to schedule. 110 | // 111 | // The updates can be for future, predicted arrival/departure events, or for 112 | // past events that already occurred. 113 | // Normally, updates should get more precise and more certain (see 114 | // uncertainty below) as the events gets closer to current time. 115 | // Even if that is not possible, the information for past events should be 116 | // precise and certain. In particular, if an update points to time in the past 117 | // but its update's uncertainty is not 0, the client should conclude that the 118 | // update is a (wrong) prediction and that the trip has not completed yet. 119 | // 120 | // Note that the update can describe a trip that is already completed. 121 | // To this end, it is enough to provide an update for the last stop of the trip. 122 | // If the time of that is in the past, the client will conclude from that that 123 | // the whole trip is in the past (it is possible, although inconsequential, to 124 | // also provide updates for preceding stops). 125 | // This option is most relevant for a trip that has completed ahead of schedule, 126 | // but according to the schedule, the trip is still proceeding at the current 127 | // time. Removing the updates for this trip could make the client assume 128 | // that the trip is still proceeding. 129 | // Note that the feed provider is allowed, but not required, to purge past 130 | // updates - this is one case where this would be practically useful. 131 | message TripUpdate { 132 | // The Trip that this message applies to. There can be at most one 133 | // TripUpdate entity for each actual trip instance. 134 | // If there is none, that means there is no prediction information available. 135 | // It does *not* mean that the trip is progressing according to schedule. 136 | required TripDescriptor trip = 1; 137 | 138 | // Additional information on the vehicle that is serving this trip. 139 | optional VehicleDescriptor vehicle = 3; 140 | 141 | // Timing information for a single predicted event (either arrival or 142 | // departure). 143 | // Timing consists of delay and/or estimated time, and uncertainty. 144 | // - delay should be used when the prediction is given relative to some 145 | // existing schedule in GTFS. 146 | // - time should be given whether there is a predicted schedule or not. If 147 | // both time and delay are specified, time will take precedence 148 | // (although normally, time, if given for a scheduled trip, should be 149 | // equal to scheduled time in GTFS + delay). 150 | // 151 | // Uncertainty applies equally to both time and delay. 152 | // The uncertainty roughly specifies the expected error in true delay (but 153 | // note, we don't yet define its precise statistical meaning). It's possible 154 | // for the uncertainty to be 0, for example for trains that are driven under 155 | // computer timing control. 156 | message StopTimeEvent { 157 | // Delay (in seconds) can be positive (meaning that the vehicle is late) or 158 | // negative (meaning that the vehicle is ahead of schedule). Delay of 0 159 | // means that the vehicle is exactly on time. 160 | optional int32 delay = 1; 161 | 162 | // Event as absolute time. 163 | // In Unix time (i.e., number of seconds since January 1st 1970 00:00:00 164 | // UTC). 165 | optional int64 time = 2; 166 | 167 | // If uncertainty is omitted, it is interpreted as unknown. 168 | // If the prediction is unknown or too uncertain, the delay (or time) field 169 | // should be empty. In such case, the uncertainty field is ignored. 170 | // To specify a completely certain prediction, set its uncertainty to 0. 171 | optional int32 uncertainty = 3; 172 | 173 | // The extensions namespace allows 3rd-party developers to extend the 174 | // GTFS-realtime specification in order to add and evaluate new features 175 | // and modifications to the spec. 176 | extensions 1000 to 1999; 177 | } 178 | 179 | // Realtime update for arrival and/or departure events for a given stop on a 180 | // trip. Updates can be supplied for both past and future events. 181 | // The producer is allowed, although not required, to drop past events. 182 | message StopTimeUpdate { 183 | // The update is linked to a specific stop either through stop_sequence or 184 | // stop_id, so one of the fields below must necessarily be set. 185 | // See the documentation in TripDescriptor for more information. 186 | 187 | // Must be the same as in stop_times.txt in the corresponding GTFS feed. 188 | optional uint32 stop_sequence = 1; 189 | // Must be the same as in stops.txt in the corresponding GTFS feed. 190 | optional string stop_id = 4; 191 | 192 | optional StopTimeEvent arrival = 2; 193 | optional StopTimeEvent departure = 3; 194 | 195 | // The relation between this StopTime and the static schedule. 196 | enum ScheduleRelationship { 197 | // The vehicle is proceeding in accordance with its static schedule of 198 | // stops, although not necessarily according to the times of the schedule. 199 | // At least one of arrival and departure must be provided. If the schedule 200 | // for this stop contains both arrival and departure times then so must 201 | // this update. 202 | SCHEDULED = 0; 203 | 204 | // The stop is skipped, i.e., the vehicle will not stop at this stop. 205 | // Arrival and departure are optional. 206 | SKIPPED = 1; 207 | 208 | // No data is given for this stop. The main intention for this value is to 209 | // give the predictions only for part of a trip, i.e., if the last update 210 | // for a trip has a NO_DATA specifier, then StopTimes for the rest of the 211 | // stops in the trip are considered to be unspecified as well. 212 | // Neither arrival nor departure should be supplied. 213 | NO_DATA = 2; 214 | } 215 | optional ScheduleRelationship schedule_relationship = 5 216 | [default = SCHEDULED]; 217 | 218 | // The extensions namespace allows 3rd-party developers to extend the 219 | // GTFS-realtime specification in order to add and evaluate new features 220 | // and modifications to the spec. 221 | extensions 1000 to 1999; 222 | } 223 | 224 | // Updates to StopTimes for the trip (both future, i.e., predictions, and in 225 | // some cases, past ones, i.e., those that already happened). 226 | // The updates must be sorted by stop_sequence, and apply for all the 227 | // following stops of the trip up to the next specified one. 228 | // 229 | // Example 1: 230 | // For a trip with 20 stops, a StopTimeUpdate with arrival delay and departure 231 | // delay of 0 for stop_sequence of the current stop means that the trip is 232 | // exactly on time. 233 | // 234 | // Example 2: 235 | // For the same trip instance, 3 StopTimeUpdates are provided: 236 | // - delay of 5 min for stop_sequence 3 237 | // - delay of 1 min for stop_sequence 8 238 | // - delay of unspecified duration for stop_sequence 10 239 | // This will be interpreted as: 240 | // - stop_sequences 3,4,5,6,7 have delay of 5 min. 241 | // - stop_sequences 8,9 have delay of 1 min. 242 | // - stop_sequences 10,... have unknown delay. 243 | repeated StopTimeUpdate stop_time_update = 2; 244 | 245 | // Moment at which the vehicle's real-time progress was measured. In POSIX 246 | // time (i.e., the number of seconds since January 1st 1970 00:00:00 UTC). 247 | optional uint64 timestamp = 4; 248 | 249 | // The current schedule deviation for the trip. Delay should only be 250 | // specified when the prediction is given relative to some existing schedule 251 | // in GTFS. 252 | // 253 | // Delay (in seconds) can be positive (meaning that the vehicle is late) or 254 | // negative (meaning that the vehicle is ahead of schedule). Delay of 0 255 | // means that the vehicle is exactly on time. 256 | // 257 | // Delay information in StopTimeUpdates take precedent of trip-level delay 258 | // information, such that trip-level delay is only propagated until the next 259 | // stop along the trip with a StopTimeUpdate delay value specified. 260 | // 261 | // Feed providers are strongly encouraged to provide a TripUpdate.timestamp 262 | // value indicating when the delay value was last updated, in order to 263 | // evaluate the freshness of the data. 264 | // 265 | // NOTE: This field is still experimental, and subject to change. It may be 266 | // formally adopted in the future. 267 | optional int32 delay = 5; 268 | 269 | // The extensions namespace allows 3rd-party developers to extend the 270 | // GTFS-realtime specification in order to add and evaluate new features and 271 | // modifications to the spec. 272 | extensions 1000 to 1999; 273 | } 274 | 275 | // Realtime positioning information for a given vehicle. 276 | message VehiclePosition { 277 | // The Trip that this vehicle is serving. 278 | // Can be empty or partial if the vehicle can not be identified with a given 279 | // trip instance. 280 | optional TripDescriptor trip = 1; 281 | 282 | // Additional information on the vehicle that is serving this trip. 283 | optional VehicleDescriptor vehicle = 8; 284 | 285 | // Current position of this vehicle. 286 | optional Position position = 2; 287 | 288 | // The stop sequence index of the current stop. The meaning of 289 | // current_stop_sequence (i.e., the stop that it refers to) is determined by 290 | // current_status. 291 | // If current_status is missing IN_TRANSIT_TO is assumed. 292 | optional uint32 current_stop_sequence = 3; 293 | // Identifies the current stop. The value must be the same as in stops.txt in 294 | // the corresponding GTFS feed. 295 | optional string stop_id = 7; 296 | 297 | enum VehicleStopStatus { 298 | // The vehicle is just about to arrive at the stop (on a stop 299 | // display, the vehicle symbol typically flashes). 300 | INCOMING_AT = 0; 301 | 302 | // The vehicle is standing at the stop. 303 | STOPPED_AT = 1; 304 | 305 | // The vehicle has departed and is in transit to the next stop. 306 | IN_TRANSIT_TO = 2; 307 | } 308 | // The exact status of the vehicle with respect to the current stop. 309 | // Ignored if current_stop_sequence is missing. 310 | optional VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO]; 311 | 312 | // Moment at which the vehicle's position was measured. In POSIX time 313 | // (i.e., number of seconds since January 1st 1970 00:00:00 UTC). 314 | optional uint64 timestamp = 5; 315 | 316 | // Congestion level that is affecting this vehicle. 317 | enum CongestionLevel { 318 | UNKNOWN_CONGESTION_LEVEL = 0; 319 | RUNNING_SMOOTHLY = 1; 320 | STOP_AND_GO = 2; 321 | CONGESTION = 3; 322 | SEVERE_CONGESTION = 4; // People leaving their cars. 323 | } 324 | optional CongestionLevel congestion_level = 6; 325 | 326 | // The degree of passenger occupancy of the vehicle. This field is still 327 | // experimental, and subject to change. It may be formally adopted in the 328 | // future. 329 | enum OccupancyStatus { 330 | // The vehicle is considered empty by most measures, and has few or no 331 | // passengers onboard, but is still accepting passengers. 332 | EMPTY = 0; 333 | 334 | // The vehicle has a relatively large percentage of seats available. 335 | // What percentage of free seats out of the total seats available is to be 336 | // considered large enough to fall into this category is determined at the 337 | // discretion of the producer. 338 | MANY_SEATS_AVAILABLE = 1; 339 | 340 | // The vehicle has a relatively small percentage of seats available. 341 | // What percentage of free seats out of the total seats available is to be 342 | // considered small enough to fall into this category is determined at the 343 | // discretion of the feed producer. 344 | FEW_SEATS_AVAILABLE = 2; 345 | 346 | // The vehicle can currently accommodate only standing passengers. 347 | STANDING_ROOM_ONLY = 3; 348 | 349 | // The vehicle can currently accommodate only standing passengers 350 | // and has limited space for them. 351 | CRUSHED_STANDING_ROOM_ONLY = 4; 352 | 353 | // The vehicle is considered full by most measures, but may still be 354 | // allowing passengers to board. 355 | FULL = 5; 356 | 357 | // The vehicle is not accepting additional passengers. 358 | NOT_ACCEPTING_PASSENGERS = 6; 359 | 360 | } 361 | optional OccupancyStatus occupancy_status = 9; 362 | 363 | // The extensions namespace allows 3rd-party developers to extend the 364 | // GTFS-realtime specification in order to add and evaluate new features and 365 | // modifications to the spec. 366 | extensions 1000 to 1999; 367 | } 368 | 369 | // An alert, indicating some sort of incident in the public transit network. 370 | message Alert { 371 | // Time when the alert should be shown to the user. If missing, the 372 | // alert will be shown as long as it appears in the feed. 373 | // If multiple ranges are given, the alert will be shown during all of them. 374 | repeated TimeRange active_period = 1; 375 | 376 | // Entities whose users we should notify of this alert. 377 | repeated EntitySelector informed_entity = 5; 378 | 379 | // Cause of this alert. 380 | enum Cause { 381 | UNKNOWN_CAUSE = 1; 382 | OTHER_CAUSE = 2; // Not machine-representable. 383 | TECHNICAL_PROBLEM = 3; 384 | STRIKE = 4; // Public transit agency employees stopped working. 385 | DEMONSTRATION = 5; // People are blocking the streets. 386 | ACCIDENT = 6; 387 | HOLIDAY = 7; 388 | WEATHER = 8; 389 | MAINTENANCE = 9; 390 | CONSTRUCTION = 10; 391 | POLICE_ACTIVITY = 11; 392 | MEDICAL_EMERGENCY = 12; 393 | } 394 | optional Cause cause = 6 [default = UNKNOWN_CAUSE]; 395 | 396 | // What is the effect of this problem on the affected entity. 397 | enum Effect { 398 | NO_SERVICE = 1; 399 | REDUCED_SERVICE = 2; 400 | 401 | // We don't care about INsignificant delays: they are hard to detect, have 402 | // little impact on the user, and would clutter the results as they are too 403 | // frequent. 404 | SIGNIFICANT_DELAYS = 3; 405 | 406 | DETOUR = 4; 407 | ADDITIONAL_SERVICE = 5; 408 | MODIFIED_SERVICE = 6; 409 | OTHER_EFFECT = 7; 410 | UNKNOWN_EFFECT = 8; 411 | STOP_MOVED = 9; 412 | } 413 | optional Effect effect = 7 [default = UNKNOWN_EFFECT]; 414 | 415 | // The URL which provides additional information about the alert. 416 | optional TranslatedString url = 8; 417 | 418 | // Alert header. Contains a short summary of the alert text as plain-text. 419 | optional TranslatedString header_text = 10; 420 | 421 | // Full description for the alert as plain-text. The information in the 422 | // description should add to the information of the header. 423 | optional TranslatedString description_text = 11; 424 | 425 | // The extensions namespace allows 3rd-party developers to extend the 426 | // GTFS-realtime specification in order to add and evaluate new features 427 | // and modifications to the spec. 428 | extensions 1000 to 1999; 429 | } 430 | 431 | // 432 | // Low level data structures used above. 433 | // 434 | 435 | // A time interval. The interval is considered active at time 't' if 't' is 436 | // greater than or equal to the start time and less than the end time. 437 | message TimeRange { 438 | // Start time, in POSIX time (i.e., number of seconds since January 1st 1970 439 | // 00:00:00 UTC). 440 | // If missing, the interval starts at minus infinity. 441 | optional uint64 start = 1; 442 | 443 | // End time, in POSIX time (i.e., number of seconds since January 1st 1970 444 | // 00:00:00 UTC). 445 | // If missing, the interval ends at plus infinity. 446 | optional uint64 end = 2; 447 | 448 | // The extensions namespace allows 3rd-party developers to extend the 449 | // GTFS-realtime specification in order to add and evaluate new features and 450 | // modifications to the spec. 451 | extensions 1000 to 1999; 452 | } 453 | 454 | // A position. 455 | message Position { 456 | // Degrees North, in the WGS-84 coordinate system. 457 | required float latitude = 1; 458 | 459 | // Degrees East, in the WGS-84 coordinate system. 460 | required float longitude = 2; 461 | 462 | // Bearing, in degrees, clockwise from North, i.e., 0 is North and 90 is East. 463 | // This can be the compass bearing, or the direction towards the next stop 464 | // or intermediate location. 465 | // This should not be direction deduced from the sequence of previous 466 | // positions, which can be computed from previous data. 467 | optional float bearing = 3; 468 | 469 | // Odometer value, in meters. 470 | optional double odometer = 4; 471 | // Momentary speed measured by the vehicle, in meters per second. 472 | optional float speed = 5; 473 | 474 | // The extensions namespace allows 3rd-party developers to extend the 475 | // GTFS-realtime specification in order to add and evaluate new features and 476 | // modifications to the spec. 477 | extensions 1000 to 1999; 478 | } 479 | 480 | // A descriptor that identifies an instance of a GTFS trip, or all instances of 481 | // a trip along a route. 482 | // - To specify a single trip instance, the trip_id (and if necessary, 483 | // start_time) is set. If route_id is also set, then it should be same as one 484 | // that the given trip corresponds to. 485 | // - To specify all the trips along a given route, only the route_id should be 486 | // set. Note that if the trip_id is not known, then stop sequence ids in 487 | // TripUpdate are not sufficient, and stop_ids must be provided as well. In 488 | // addition, absolute arrival/departure times must be provided. 489 | message TripDescriptor { 490 | // The trip_id from the GTFS feed that this selector refers to. 491 | // For non frequency-based trips, this field is enough to uniquely identify 492 | // the trip. For frequency-based trip, start_time and start_date might also be 493 | // necessary. 494 | optional string trip_id = 1; 495 | 496 | // The route_id from the GTFS that this selector refers to. 497 | optional string route_id = 5; 498 | 499 | // The initially scheduled start time of this trip instance. 500 | // When the trip_id corresponds to a non-frequency-based trip, this field 501 | // should either be omitted or be equal to the value in the GTFS feed. When 502 | // the trip_id correponds to a frequency-based trip, the start_time must be 503 | // specified for trip updates and vehicle positions. If the trip corresponds 504 | // to exact_times=1 GTFS record, then start_time must be some multiple 505 | // (including zero) of headway_secs later than frequencies.txt start_time for 506 | // the corresponding time period. If the trip corresponds to exact_times=0, 507 | // then its start_time may be arbitrary, and is initially expected to be the 508 | // first departure of the trip. Once established, the start_time of this 509 | // frequency-based trip should be considered immutable, even if the first 510 | // departure time changes -- that time change may instead be reflected in a 511 | // StopTimeUpdate. 512 | // Format and semantics of the field is same as that of 513 | // GTFS/frequencies.txt/start_time, e.g., 11:15:35 or 25:15:35. 514 | optional string start_time = 2; 515 | // The scheduled start date of this trip instance. 516 | // Must be provided to disambiguate trips that are so late as to collide with 517 | // a scheduled trip on a next day. For example, for a train that departs 8:00 518 | // and 20:00 every day, and is 12 hours late, there would be two distinct 519 | // trips on the same time. 520 | // This field can be provided but is not mandatory for schedules in which such 521 | // collisions are impossible - for example, a service running on hourly 522 | // schedule where a vehicle that is one hour late is not considered to be 523 | // related to schedule anymore. 524 | // In YYYYMMDD format. 525 | optional string start_date = 3; 526 | 527 | // The relation between this trip and the static schedule. If a trip is done 528 | // in accordance with temporary schedule, not reflected in GTFS, then it 529 | // shouldn't be marked as SCHEDULED, but likely as ADDED. 530 | enum ScheduleRelationship { 531 | // Trip that is running in accordance with its GTFS schedule, or is close 532 | // enough to the scheduled trip to be associated with it. 533 | SCHEDULED = 0; 534 | 535 | // An extra trip that was added in addition to a running schedule, for 536 | // example, to replace a broken vehicle or to respond to sudden passenger 537 | // load. 538 | ADDED = 1; 539 | 540 | // A trip that is running with no schedule associated to it, for example, if 541 | // there is no schedule at all. 542 | UNSCHEDULED = 2; 543 | 544 | // A trip that existed in the schedule but was removed. 545 | CANCELED = 3; 546 | 547 | } 548 | optional ScheduleRelationship schedule_relationship = 4; 549 | 550 | // The extensions namespace allows 3rd-party developers to extend the 551 | // GTFS-realtime specification in order to add and evaluate new features and 552 | // modifications to the spec. 553 | extensions 1000 to 1999; 554 | } 555 | 556 | // Identification information for the vehicle performing the trip. 557 | message VehicleDescriptor { 558 | // Internal system identification of the vehicle. Should be unique per 559 | // vehicle, and can be used for tracking the vehicle as it proceeds through 560 | // the system. 561 | optional string id = 1; 562 | 563 | // User visible label, i.e., something that must be shown to the passenger to 564 | // help identify the correct vehicle. 565 | optional string label = 2; 566 | 567 | // The license plate of the vehicle. 568 | optional string license_plate = 3; 569 | 570 | // The extensions namespace allows 3rd-party developers to extend the 571 | // GTFS-realtime specification in order to add and evaluate new features and 572 | // modifications to the spec. 573 | extensions 1000 to 1999; 574 | } 575 | 576 | // A selector for an entity in a GTFS feed. 577 | message EntitySelector { 578 | // The values of the fields should correspond to the appropriate fields in the 579 | // GTFS feed. 580 | // At least one specifier must be given. If several are given, then the 581 | // matching has to apply to all the given specifiers. 582 | optional string agency_id = 1; 583 | optional string route_id = 2; 584 | // corresponds to route_type in GTFS. 585 | optional int32 route_type = 3; 586 | optional TripDescriptor trip = 4; 587 | optional string stop_id = 5; 588 | 589 | // The extensions namespace allows 3rd-party developers to extend the 590 | // GTFS-realtime specification in order to add and evaluate new features and 591 | // modifications to the spec. 592 | extensions 1000 to 1999; 593 | } 594 | 595 | // An internationalized message containing per-language versions of a snippet of 596 | // text or a URL. 597 | // One of the strings from a message will be picked up. The resolution proceeds 598 | // as follows: 599 | // 1. If the UI language matches the language code of a translation, 600 | // the first matching translation is picked. 601 | // 2. If a default UI language (e.g., English) matches the language code of a 602 | // translation, the first matching translation is picked. 603 | // 3. If some translation has an unspecified language code, that translation is 604 | // picked. 605 | message TranslatedString { 606 | message Translation { 607 | // A UTF-8 string containing the message. 608 | required string text = 1; 609 | // BCP-47 language code. Can be omitted if the language is unknown or if 610 | // no i18n is done at all for the feed. At most one translation is 611 | // allowed to have an unspecified language tag. 612 | optional string language = 2; 613 | 614 | // The extensions namespace allows 3rd-party developers to extend the 615 | // GTFS-realtime specification in order to add and evaluate new features and 616 | // modifications to the spec. 617 | extensions 1000 to 1999; 618 | } 619 | // At least one translation must be provided. 620 | repeated Translation translation = 1; 621 | 622 | // The extensions namespace allows 3rd-party developers to extend the 623 | // GTFS-realtime specification in order to add and evaluate new features and 624 | // modifications to the spec. 625 | extensions 1000 to 1999; 626 | } 627 | -------------------------------------------------------------------------------- /nyct-subway.proto.txt: -------------------------------------------------------------------------------- 1 | // 2 | // NYCT Subway extensions for the GTFS-realtime protocol. 3 | // 4 | option java_package = "com.google.transit.realtime"; 5 | 6 | import "gtfs-realtime.proto.txt"; 7 | 8 | message TripReplacementPeriod { 9 | // The replacement period is for this route 10 | optional string route_id = 1; 11 | // The start time is omitted, the end time is currently now + 30 minutes for 12 | // all routes of the A division 13 | optional transit_realtime.TimeRange replacement_period = 2; 14 | } 15 | 16 | // NYCT Subway extensions for the feed header 17 | message NyctFeedHeader { 18 | // Version of the NYCT Subway extensions 19 | // The current version is 1.0 20 | required string nyct_subway_version = 1; 21 | // For the NYCT Subway, the GTFS-realtime feed replaces any scheduled 22 | // trip within the trip_replacement_period. 23 | // This feed is a full dataset, it contains all trips starting 24 | // in the trip_replacement_period. If a trip from the static GTFS is not 25 | // found in the GTFS-realtime feed, it should be considered as cancelled. 26 | // The replacement period can be different for each route, so here is 27 | // a list of the routes where the trips in the feed replace all 28 | // scheduled trips within the replacement period. 29 | repeated TripReplacementPeriod trip_replacement_period = 2; 30 | } 31 | 32 | extend transit_realtime.FeedHeader { 33 | optional NyctFeedHeader nyct_feed_header = 1001; 34 | } 35 | 36 | // NYCT Subway extensions for the trip descriptor 37 | message NyctTripDescriptor { 38 | // The nyct_train_id is meant for internal use only. It provides an 39 | // easy way to associated GTFS-realtime trip identifiers with NYCT rail 40 | // operations identifier 41 | // 42 | // The ATS office system assigns unique train identification (Train ID) to 43 | // each train operating within or ready to enter the mainline of the 44 | // monitored territory. An example of this is 06 0123+ PEL/BBR and is decoded 45 | // as follows: 46 | // 47 | // The first character represents the trip type designator. 0 identifies a 48 | // scheduled revenue trip. Other revenue trip values that are a result of a 49 | // change to the base schedule include; [= reroute], [/ skip stop], [$ turn 50 | // train] also known as shortly lined service. 51 | // 52 | // The second character 6 represents the trip line i.e. number 6 train The 53 | // third set of characters identify the decoded origin time. The last 54 | // character may be blank "on the whole minute" or + "30 seconds" 55 | // 56 | // Note: Origin times will not change when there is a trip type change. This 57 | // is followed by a three character "Origin Location" / "Destination 58 | // Location" 59 | optional string train_id = 1; 60 | 61 | // This trip has been assigned to a physical train. If true, this trip is 62 | // already underway or most likely will depart shortly. 63 | // 64 | // Train Assignment is a function of the Automatic Train Supervision (ATS) 65 | // office system used by NYCT Rail Operations to monitor and track train 66 | // movements. ATS provides the ability to "assign" the nyct_train_id 67 | // attribute when a physical train is at its origin terminal. These assigned 68 | // trips have the is_assigned field set in the TripDescriptor. 69 | // 70 | // When a train is at a terminal but has not been given a work program it is 71 | // declared unassigned and is tagged as such. Unassigned trains can be moved 72 | // to a storage location or assigned a nyct_train_id when a determination for 73 | // service is made. 74 | optional bool is_assigned = 2; 75 | 76 | // The direction the train is moving. 77 | enum Direction { 78 | NORTH = 1; 79 | EAST = 2; 80 | SOUTH = 3; 81 | WEST = 4; 82 | } 83 | // Uptown and Bronx-bound trains are moving NORTH. 84 | // Times Square Shuttle to Grand Central is also northbound. 85 | // 86 | // Downtown and Brooklyn-bound trains are moving SOUTH. 87 | // Times Square Shuttle to Times Square is also southbound. 88 | // 89 | // EAST and WEST are not used currently. 90 | optional Direction direction = 3; 91 | } 92 | 93 | extend transit_realtime.TripDescriptor { 94 | optional NyctTripDescriptor nyct_trip_descriptor = 1001; 95 | } 96 | 97 | // NYCT Subway extensions for the stop time update 98 | message NyctStopTimeUpdate { 99 | // Provides the planned station arrival track. The following is the Manhattan 100 | // track configurations: 101 | // 1: southbound local 102 | // 2: southbound express 103 | // 3: northbound express 104 | // 4: northbound local 105 | // 106 | // In the Bronx (except Dyre Ave line) 107 | // M: bi-directional express (in the AM express to Manhattan, in the PM 108 | // express away). 109 | // 110 | // The Dyre Ave line is configured: 111 | // 1: southbound 112 | // 2: northbound 113 | // 3: bi-directional 114 | optional string scheduled_track = 1; 115 | 116 | // This is the actual track that the train is operating on and can be used to 117 | // determine if a train is operating according to its current schedule 118 | // (plan). 119 | // 120 | // The actual track is known only shortly before the train reaches a station, 121 | // typically not before it leaves the previous station. Therefore, the NYCT 122 | // feed sets this field only for the first station of the remaining trip. 123 | // 124 | // Different actual and scheduled track is the result of manually rerouting a 125 | // train off it scheduled path. When this occurs, prediction data may become 126 | // unreliable since the train is no longer operating in accordance to its 127 | // schedule. The rules engine for the 'countdown' clocks will remove this 128 | // train from all schedule stations. 129 | optional string actual_track = 2; 130 | } 131 | 132 | extend transit_realtime.TripUpdate.StopTimeUpdate { 133 | optional NyctStopTimeUpdate nyct_stop_time_update = 1001; 134 | } 135 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mta-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "express": "^4.11.2", 8 | "morgan": "^1.5.1", 9 | "protobufjs": "^3.8.2", 10 | "socket.io": "^1.3.4", 11 | "swig": "^1.4.2", 12 | "underscore": "^1.8.1" 13 | }, 14 | "devDependencies": {}, 15 | "scripts": { 16 | "test": "echo \"Error: no test specified\" && exit 1" 17 | }, 18 | "author": "", 19 | "license": "ISC" 20 | } 21 | --------------------------------------------------------------------------------