# 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=&mapid= To query JSON: https://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=&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 ![Example Return](imgs/screenshot1.jpg) - 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=&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=&rt=&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 ![Example Return](imgs/screenshot2.jpg) - 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=&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 = 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=&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 Arduino IDE code for the API is available in example/src/