Compare commits
2 Commits
f37942d267
...
8d9ceded83
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d9ceded83 | |||
| 57d13f7fd0 |
@@ -1,2 +1,114 @@
|
||||
# CTA-Trains
|
||||
# CTA for ESP32
|
||||
## Notes
|
||||
### CTA API interface
|
||||
The CTA API can be fairly trivially queries to get a JSON response with the required metadata.
|
||||
- Docs are available here: https://www.transitchicago.com/developers/ttdocs/
|
||||
- API consists of two main queries
|
||||
- 'Arrivals' - which lets you query all arrivals for a station available at https://lapi.transitchicago.com/api/1.0/ttarrivals.aspx
|
||||
- 'Locations' - Which lets you query all stations along a line, and returns the location of all trains. Available at https://lapi.transitchicago.com/api/1.0/ttpositions.aspx
|
||||
- The API is fairly simple and robust, there's no need for tokens or 2FA or oauth, a simple custom string will provide the data needed:
|
||||
- The API in this instance is simply a HTTPS query with some parameters, you can see this by pasting the following into a browser:
|
||||
|
||||
```
|
||||
To query XML: https://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=<KEYID>&mapid=<mapID>
|
||||
To query JSON: https://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=<KEYID>&mapid=40380&outputType=JSON
|
||||
|
||||
Simple HTTP POST queries use the '?' to define start of parameters, and each parameter is seperated by an '&'
|
||||
In the above, we are querying the 'ttarrivals' endpoint, used for the Arrivals API
|
||||
KEYID is your API key
|
||||
MAPID is the ID of a station on the CTA, such as "40380". These station numbers are available on the ttdocs website.
|
||||
```
|
||||
|
||||
- The below is an example returned of the JSON station for mapid 40380, station Clarke/Lake
|
||||
|
||||

|
||||
|
||||
- The Arrivals API returns all the future trains to arrive at a station.
|
||||
- JSON is typically an easier format to work with than XML, both are essentially ways to structure data that are nicely readable by applications (a tree structure).
|
||||
- In the above example, we have an array of next arrivals, starting at the top of the tree, we can pick each like you would in a folder. Some pseudocode (i.e. made up simplified language):
|
||||
- Say return json is `output.json = https://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=<KEYID>&mapid=40380&outputType=JSON`
|
||||
- `output->ctatt` gives us tmst, errCd, errNm and eta 'folders'
|
||||
- `output->ctatt->eta` gives us a list of folders for all the next upcoming trains.
|
||||
- `output->ctatt->eta->0` gives us the next train.
|
||||
- `output->ctatt->eta->1` gives us the second to next train.
|
||||
- `output->ctatt->eta->0-arrT` gives us the time the next train will arrive in an ISO date format, i.e. "2026-07-12T00:50:16"
|
||||
- The problem with the Arrivals API, is you then need to query every station one by one, save the next arrival time of a train and then do something with the result (say, turn on an LED if it's less than 2 minutes away).
|
||||
- That's a lot of queries to check for the entire network. Especially for a little ESP32.
|
||||
- Very wasteful and abusive of the API for just your usage.
|
||||
- Enter the Locations API. Rather than query a station, we can query the entire line and get a list of trains on it.
|
||||
|
||||
```
|
||||
To query JSON: https://lapi.transitchicago.com/api/1.0/ttpositions.aspx?key=<KEYID>&rt=<route>&outputType=JSON
|
||||
|
||||
KEYID is your API key
|
||||
RT is the identifier of the line, e.g. 'Blue'. These are in the appendix on the ttdocs website.
|
||||
```
|
||||
|
||||
- The below is an example returned of the JSON station for Blue route
|
||||
|
||||

|
||||
|
||||
- The Locations API install returns all trains along a route.
|
||||
- In the above example, we have an array of all trains, starting at the top of the tree, we can pick each like you would in a folder. Some pseudocode:
|
||||
- Say return json is output.json which = https://lapi.transitchicago.com/api/1.0/ttpositions.aspx?key=<KEYID>&rt=Blue&outputType=JSON
|
||||
- `output->tmst` gives us the time we made this query, this is handy to find the current time.
|
||||
- `output->ctatt->route->0` gives us all the trains on the first route (which is Blue, as that's what we asked for)
|
||||
- `output->ctatt->route->0->train` gives us a list of folders for all the active trains.
|
||||
- `output->ctatt->route->0->train->0` gives us the first train.
|
||||
- `output->ctatt->route->0->train->1` gives us the second train.
|
||||
- `output->ctatt->route->0->train->0->nextStaNm` gives us the name of it's next station.
|
||||
- `output->ctatt->route->0->train->0->nextStaId` gives us the ID of it's next station.
|
||||
- `output->ctatt->route->0->train->0->arrT` gives us the time to the next station in ISO format. "2026-07-12T00:50:16"
|
||||
- So now, in a single query, we have all the information we need to know how far away "a train" is from any station on a line.
|
||||
- A single query tells us everything we need to know to light up a line.
|
||||
|
||||
So example pseudocode:
|
||||
```
|
||||
# Create a simple 2D array of all stations (imagine table with two columns) and when the next train arrives. Let's set arrival time to 999 for now (i.e. not any time soon).
|
||||
# We can use the station number instead of the name to keep code simpler (don't have to deal with spaces or symbols)
|
||||
stations_eta = <array>
|
||||
stations_eta[40380] = 999
|
||||
stations_eta[40390] = 999
|
||||
.... etc ....
|
||||
|
||||
# Get route data in JSON format
|
||||
output_json = http_query(https://lapi.transitchicago.com/api/1.0/ttpositions.aspx?key=<KEYID>&rt=Blue&outputType=JSON)
|
||||
|
||||
# Get that into a useful array format instead of just a blob
|
||||
output = json(output_json)
|
||||
|
||||
# We need the time this query was generated to be used for math later. Fortunately the API response stores this
|
||||
time_now = output->tmst
|
||||
|
||||
# Now we can loop through all the trains and match up to the stations
|
||||
for train in output->ctatt->route->0->train:
|
||||
# 'train' will now refer to the first train in the folder, aka 0.
|
||||
# So we can save the next stop of the train
|
||||
next_stop = train->nextStaId
|
||||
# The time of the next stop
|
||||
time_to_stop = train->arrT
|
||||
# Get the time difference.
|
||||
time_eta = time_to_stop - time_now
|
||||
# In our made up language, this is going to be in seconds.
|
||||
time_eta_mins = time_eta / 60
|
||||
|
||||
# Now we can update the station array from earlier
|
||||
stations_eta[next_stop] = time_eta_mins
|
||||
|
||||
# The loop will now run again, but next time it will refer to the second train (aka 1)
|
||||
|
||||
# We now have an array of all stations and the next train to arrive at them. For the ones with none any time soon, they'll still be 999 minutes away.
|
||||
print(stations_eta[40380])
|
||||
---> 6
|
||||
|
||||
print(stations_eta[40390])
|
||||
---> 11
|
||||
```
|
||||
|
||||
### ESP32 Implementation
|
||||
- Micropython appears to still be poorly documented for ESP32s (especially the aliexpress clone boards).
|
||||
- Recommendation is to use either the Arduino IDE (for quickly getting going) or using PlatformIO with VS Code.
|
||||
- Both of these are just fancy wrappers around C++ language, so plenty of documentation to google.
|
||||
- The latter is harder to initially get going (mostly cause of VS Code), but it's a much nicer environment to code in than Arduino IDE.
|
||||
- PlatformIO is completely compatable with Arduino code, so can always start in Arduino IDE and move from there.
|
||||
- Example PlatformIO code for the API is available in example/src/
|
||||
Reference in New Issue
Block a user