├── README.md └── schema ├── routeTelemetry.json └── vehicleTelemetry.json /README.md: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | This guide explains how to use the API that exposes realtime location data for public transport in Chișinău. The highlights: 5 | 6 | - It follows the publish-subscribe pattern 7 | - MQTT is used for messaging 8 | - Payloads are in JSON 9 | - Vehicles send telemetry every ~3s 10 | - Community support is available via [chat](https://roataway.zulipchat.com/) 11 | 12 | 13 | Why is this an open API? 14 | ------------------------ 15 | 16 | Although the requirements for the public transport tracking system did not ask for it, someone went the extra mile to make it so. Public transport software is too important to be left in the hands of a single company. An open protocol enables others to roll out their own products that rely on the data - these can have more features, look nicer, or come up with innovative uses of the data that others have not thought of. Thus, consumers are less likely to end up using an outdated or abandoned application that does not keep up with progress. 17 | 18 | 19 | Prerequisites 20 | ------------- 21 | 22 | You will be more productive as you go through this guide, if you familiarize yourself with these first: 23 | 24 | - Vehicle metadata, shared via [vehicles.csv](https://github.com/roataway/infrastructure-data/blob/master/vehicles.csv) 25 | - Route metadata, shared via [routes.csv](https://github.com/roataway/infrastructure-data/blob/master/routes.csv) 26 | - A basic understanding of the [MQTT protocol](https://www.hivemq.com/blog/mqtt-essentials-part-1-introducing-mqtt/) 27 | 28 | 29 | Technical overview 30 | ================== 31 | 32 | Every subscriber will receive the same data, as soon as a vehicle sends the information. You can have multiple subscriptions simultaneously, as well as run multiple instances of your clients. 33 | 34 | ``` 35 | +----------+ 36 | +----------+ publish | | 37 | | GPS | telemetry | MQTT | 38 | | tracker +----------------> broker | 39 | | | | | 40 | +----------+ | | 41 | | | 42 | +-+--+---+-+ 43 | | | | 44 | +-----------------+ | | 45 | | | +-------------+ 46 | | | | 47 | +-----------v-----+ +-----------v-----+ +-----v-------+ 48 | | MQTT subscriber | | Another | | Yet | 49 | | (your software) | | MQTT subscriber | .. | another | 50 | | | | | | MQTT | 51 | | | | | | subscriber | 52 | +-----------------+ +-----------------+ +-------------+ 53 | ``` 54 | 55 | 56 | A subscription requires a topic name, here are the ones you can use: 57 | 58 | `telemetry/transport/+` 59 | ----------------------- 60 | 61 | It distributes raw telemetry coming directly from each vehicle, the last element in the topic name will be the tracker ID. Refer to `vehicles.csv` to link the tracker ID to an actual vehicle. 62 | 63 | For example, if the topic is `telemetry/transport/000001`, the tracker ID is `000001`, it is attached to trolleybus `1273` (the transport company itself, e.g., RTEC, refers to this as a "board number"). 64 | 65 | 66 | All messages are JSON strings which contain the following keys: 67 | 68 | | Field | Type | Notes | 69 | |-------------|-------|------------------------------------------------------------------------| 70 | | `latitude` | float | | 71 | | `longitude` | float | | 72 | | `direction` | float | | 73 | | `speed` | int | In km/h | 74 | | `timestamp` | str | In UTC, e.g. `2019-08-18T16:42:29Z` the format is `%Y-%m-%dT%H:%M:%SZ` | 75 | 76 | 77 | Example: 78 | 79 | ```json 80 | { 81 | "longitude": 28.887143, 82 | "latitude": 47.026044, 83 | "timestamp": "2019-08-18T16:42:29Z", 84 | "speed": 0, 85 | "direction": 0.0 86 | } 87 | ``` 88 | 89 | Warning: 90 | 91 | The payloads may contain other, undocumented keys - don't count on them. However, treat this document like an RFC and keep in mind that you can argue for the inclusion of new attributes and modifications in the protocol. 92 | 93 | 94 | `telemetry/route/+` 95 | ------------------- 96 | 97 | It distributes slightly enriched telemetry, grouped by route. The last element in the topic name is the `route_upstream_id` that you will find in `routes.csv`. 98 | 99 | For example, if the topic is `telemetry/route/1`, the upstream route ID is `1`, it corresponds to route `30, Aeroport - Piața Marii Adunări Naționale`. 100 | 101 | This is what the payloads look like: 102 | 103 | 104 | | Field | Type | Notes | 105 | |-------------|-------|------------------------------------------------------------------------| 106 | | `latitude` | float | | 107 | | `longitude` | float | | 108 | | `direction` | float | | 109 | | `speed` | int | In km/h | 110 | | `timestamp` | str | In UTC, e.g. `2019-08-18T16:42:29Z` the format is `%Y-%m-%dT%H:%M:%SZ` | 111 | | `board` | str | The board number of the vehicle | 112 | | `rtu_id` | str | The tracker ID | 113 | | `route` | str | The route name (not to be confused with `route_upstream_id`!) | 114 | 115 | 116 | Example: 117 | 118 | ```json 119 | { 120 | "latitude": 46.98579, 121 | "longitude": 28.857805, 122 | "timestamp": "2019-10-22T07:06:04Z", 123 | "speed": 12, 124 | "direction": 313.5, 125 | "board": "1308", 126 | "rtu_id": "0000019", 127 | "route": "3" 128 | } 129 | ``` 130 | 131 | Note: 132 | 133 | - If a vehicle is moved from one route to another, its telemetry will be automatically distributed via a topic that corresponds to the new route. 134 | - You can subscribe to individual routes, by using their id in the topic name, e.g., `telemetry/route/1`. 135 | - `board`, `rtu_id` and `route` are usually numerical values, but they can also contain letters, treat them as strings! 136 | 137 | Warning: 138 | 139 | The payloads may contain other, undocumented keys - don't count on them. 140 | 141 | 142 | `event/route/+` 143 | ---------------- 144 | 145 | This topic disseminates information about recent changes related to a particular route, for example: a vehicle was taken off the route, or added to it. These details allow displays to be updated accordingly, to provide a smooth user experience. For example, if a vehicle was taken off a particular route, an application will mark it as such. 146 | 147 | | Field | Type | Notes | 148 | |-------------|-------|------------------------------------------------------------------------| 149 | | `event` | str | Only `remove` events are considered, new ones might be added later. | 150 | | `board` | str | The board number of the vehicle | 151 | | `rtu_id` | str | The tracker ID | 152 | 153 | Example that shows what happens when board `1308`, was removed from its current route: 154 | 155 | ```json 156 | { 157 | "event": "remove", 158 | "board": "1308", 159 | "rtu_id": "0000019", 160 | } 161 | ``` 162 | 163 | Give it a try 164 | ============= 165 | 166 | You can use any MQTT client to subscribe to the topics above and see the live data. In these examples we shall use `mosquitto_sub`, distributed with the Mosquitto broker. On Debian-based systems you can install it with `sudo apt install mosquitto-clients`. Here's how to run it: 167 | 168 | 169 | - `mosquitto_sub -v -h opendata.dekart.com -p 1945 -t telemetry/transport/+` - receive raw telemetry 170 | - `mosquitto_sub -v -h opendata.dekart.com -p 1945 -t telemetry/route/+` - receive route-centric telemetry 171 | - `mosquitto_sub -v -h opendata.dekart.com -p 1945 -t event/route/+` - receive notifications when a vehicle was taken off a route 172 | 173 | You can also try `opendata.dekart.com:1946` for MQTT over plaintext websockets. 174 | 175 | 176 | Credits 177 | ======= 178 | 179 | We thank [Dekart](https://dekart.com) for designing a system based on non-proprietary protocols and for opening it up to the public. 180 | 181 | References 182 | ========== 183 | 184 | - MQTT libraries for different [programming languages](https://www.eclipse.org/paho/downloads.php). 185 | - Reference implementation that visualizes the [vehicles on a map](https://roataway.md). 186 | -------------------------------------------------------------------------------- /schema/routeTelemetry.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema":"http://json-schema.org/draft-07/schema#", 3 | "$id":"http://roataway.md/schema/routeTelemetry.json", 4 | "type":"object", 5 | "title":"Route-centric vehicle telemetry schema", 6 | "required":[ 7 | "longitude", 8 | "latitude", 9 | "timestamp", 10 | "speed", 11 | "direction" 12 | ], 13 | "properties":{ 14 | "longitude":{ 15 | "$id":"#/properties/longitude", 16 | "type":"number", 17 | "minimum":-180.0, 18 | "maximum":180.0, 19 | "title":"Longitude", 20 | "examples":[ 21 | 28.887143 22 | ] 23 | }, 24 | "latitude":{ 25 | "$id":"#/properties/latitude", 26 | "type":"number", 27 | "minimum":-90.0, 28 | "maximum":90.0, 29 | "title":"Latitude", 30 | "examples":[ 31 | 47.026044 32 | ] 33 | }, 34 | "timestamp":{ 35 | "$id":"#/properties/timestamp", 36 | "type":"string", 37 | "format":"date-time", 38 | "title":"Timestamp", 39 | "description":"Format ISO 8601, YYYY-MM-DDTHH:MM:SSZ", 40 | "examples":[ 41 | "2019-08-18T16:42:29Z" 42 | ], 43 | "pattern":"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$" 44 | }, 45 | "speed":{ 46 | "$id":"#/properties/speed", 47 | "type":"integer", 48 | "minimum":0, 49 | "maximum":200, 50 | "title":"Speed km/h", 51 | "examples":[ 52 | 0 53 | ] 54 | }, 55 | "direction":{ 56 | "$id":"#/properties/direction", 57 | "type":"number", 58 | "minimum":0, 59 | "maximum":360, 60 | "title":"Vehicle movement direction degree", 61 | "examples":[ 62 | 180.8 63 | ] 64 | }, 65 | "board":{ 66 | "$id":"#/properties/board", 67 | "type":"string", 68 | "minLength":4, 69 | "maxLength":10, 70 | "title":"Board identifier", 71 | "description":"typically a number but can be a string", 72 | "examples":[ 73 | "2181" 74 | ] 75 | }, 76 | "rtu_id":{ 77 | "$id":"#/properties/rtu_id", 78 | "type":"string", 79 | "minLength":3, 80 | "maxLength":10, 81 | "title":"Unique tracker identifier", 82 | "examples":[ 83 | "0000154" 84 | ] 85 | }, 86 | "route":{ 87 | "$id":"#/properties/route", 88 | "type":"string", 89 | "minLength":1, 90 | "maxLength":5, 91 | "title":"Route", 92 | "examples":[ 93 | "8", 94 | "6G" 95 | ] 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /schema/vehicleTelemetry.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema":"http://json-schema.org/draft-07/schema#", 3 | "$id":"http://roataway.md/schema/vehicleTelemetry.json", 4 | "type":"object", 5 | "title":"Vehicle telemetry schema", 6 | "required":[ 7 | "longitude", 8 | "latitude", 9 | "timestamp", 10 | "speed", 11 | "direction" 12 | ], 13 | "properties":{ 14 | "longitude":{ 15 | "$id":"#/properties/longitude", 16 | "type":"number", 17 | "minimum":-180.0, 18 | "maximum":180.0, 19 | "title":"Longitude", 20 | "examples":[ 21 | 28.887143 22 | ] 23 | }, 24 | "latitude":{ 25 | "$id":"#/properties/latitude", 26 | "type":"number", 27 | "minimum":-90.0, 28 | "maximum":90.0, 29 | "title":"Latitude", 30 | "examples":[ 31 | 47.026044 32 | ] 33 | }, 34 | "timestamp":{ 35 | "$id":"#/properties/timestamp", 36 | "type":"string", 37 | "format":"date-time", 38 | "title":"Timestamp", 39 | "description":"Format ISO 8601, YYYY-MM-DDTHH:MM:SSZ", 40 | "examples":[ 41 | "2019-08-18T16:42:29Z" 42 | ], 43 | "pattern":"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$" 44 | }, 45 | "speed":{ 46 | "$id":"#/properties/speed", 47 | "type":"integer", 48 | "minimum":0, 49 | "maximum":200, 50 | "title":"Speed km/h", 51 | "examples":[ 52 | 0 53 | ] 54 | }, 55 | "direction":{ 56 | "$id":"#/properties/direction", 57 | "type":"number", 58 | "minimum":0, 59 | "maximum":360, 60 | "title":"Vehicle movement direction degree", 61 | "examples":[ 62 | 180.8 63 | ] 64 | } 65 | } 66 | } 67 | --------------------------------------------------------------------------------