Updates for web server

This commit is contained in:
iosullivan committed 2026-10-05 19:07:50 +10:00
1 parent 37b7001099
commit bc488d444f
4 files changed
+246 -313

No files matched your search

+1 -1
View File
@@ -31,7 +31,7 @@ The CTA API can be fairly trivially queried to get a JSON response with the requ
- `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"
- `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.
@@ -0,0 +1,146 @@
# Not currently used
stations = {}
stations[41090] = { 'name':' Monroe (Red Line)', 'eta':[], 'led_index':1, 'state':0 }
stations[40820] = { 'name':' Rosemont (Blue Line)', 'eta':[], 'led_index': machine.Pin(15, machine.Pin.OUT), 'state':0 }
stations[41010] = { 'name':' Rockwell (Brown Line)', 'eta':[], 'led_index':3, 'state':0 }
stations[40470] = { 'name':' Racine (Blue Line)', 'eta':[], 'led_index':4, 'state':0 }
stations[40190] = { 'name':' Sox-35th (Red Line)', 'eta':[], 'led_index':5, 'state':0 }
stations[40020] = { 'name':' Harlem/Lake (Green Line)', 'eta':[], 'led_index':6, 'state':0 }
stations[40900] = { 'name':' Howard (Red Purple & Yellow lines)', 'eta':[], 'led_index':7, 'state':0 }
stations[41160] = { 'name':' Clinton (Green & Pink lines)', 'eta':[], 'led_index':8, 'state':0 }
stations[40230] = { 'name':' Cumberland (Blue Line)', 'eta':[], 'led_index':9, 'state':0 }
stations[40560] = { 'name':' Jackson (Red Line)', 'eta':[], 'led_index':10, 'state':0 }
stations[41150] = { 'name':' Kedzie (Orange Line)', 'eta':[], 'led_index':11, 'state':0 }
stations[40780] = { 'name':' Central Park (Pink Line)', 'eta':[], 'led_index':12, 'state':0 }
stations[41080] = { 'name':' 47th (Green Line)', 'eta':[], 'led_index':13, 'state':0 }
stations[40510] = { 'name':' Garfield (Green Line)', 'eta':[], 'led_index':14, 'state':0 }
stations[41050] = { 'name':' Linden (Purple Line)', 'eta':[], 'led_index':2, 'state':0 }
stations[40120] = { 'name':' 35th/Archer (Orange Line)', 'eta':[], 'led_index':16, 'state':0 }
stations[40570] = { 'name':' California (Blue Line)', 'eta':[], 'led_index':17, 'state':0 }
stations[40260] = { 'name':' State/Lake (Brown Green Orange Pink & Purple lines)', 'eta':[], 'led_index':18, 'state':0 }
stations[40130] = { 'name':' 51st (Green Line)', 'eta':[], 'led_index':19, 'state':0 }
stations[41700] = { 'name':' Washington/Wabash (Brown Green Orange Purple & Pink lines)', 'eta':[], 'led_index':20, 'state':0 }
stations[41000] = { 'name':' Cermak-Chinatown (Red Line)', 'eta':[], 'led_index':21, 'state':0 }
stations[40340] = { 'name':' Berwyn (Red Line)', 'eta':[], 'led_index':22, 'state':0 }
stations[41690] = { 'name':' Cermak-McCormick Place (Green Line)', 'eta':[], 'led_index':23, 'state':0 }
stations[40490] = { 'name':' Grand (Blue Line)', 'eta':[], 'led_index':24, 'state':0 }
stations[41060] = { 'name':' Ashland (Orange Line)', 'eta':[], 'led_index':25, 'state':0 }
stations[40090] = { 'name':' Damen (Brown Line)', 'eta':[], 'led_index':26, 'state':0 }
stations[41280] = { 'name':' Jefferson Park (Blue Line)', 'eta':[], 'led_index':27, 'state':0 }
stations[40520] = { 'name':' Foster (Purple Line)', 'eta':[], 'led_index':28, 'state':0 }
stations[40330] = { 'name':' Grand (Red Line)', 'eta':[], 'led_index':29, 'state':0 }
stations[40280] = { 'name':' Central (Green Line)', 'eta':[], 'led_index':30, 'state':0 }
stations[40250] = { 'name':' Kedzie-Homan (Blue Line)', 'eta':[], 'led_index':31, 'state':0 }
stations[40870] = { 'name':' Francisco (Brown Line)', 'eta':[], 'led_index':32, 'state':0 }
stations[41240] = { 'name':' Addison (Blue Line)', 'eta':[], 'led_index':33, 'state':0 }
stations[40740] = { 'name':' Western (Pink Line)', 'eta':[], 'led_index':34, 'state':0 }
stations[41360] = { 'name':' California (Green Line)', 'eta':[], 'led_index':35, 'state':0 }
stations[41400] = { 'name':' Roosevelt (Red Orange & Green lines)', 'eta':[], 'led_index':36, 'state':0 }
stations[41410] = { 'name':' Chicago (Blue Line)', 'eta':[], 'led_index':37, 'state':0 }
stations[40680] = { 'name':' Adams/Wabash (Brown Green Orange Pink & Purple lines)', 'eta':[], 'led_index':38, 'state':0 }
stations[40920] = { 'name':' Pulaski (Blue Line)', 'eta':[], 'led_index':39, 'state':0 }
stations[41210] = { 'name':' Wellington (Brown & Purple lines)', 'eta':[], 'led_index':40, 'state':0 }
stations[41340] = { 'name':' LaSalle (Blue Line)', 'eta':[], 'led_index':41, 'state':0 }
stations[41490] = { 'name':' Harrison (Red Line)', 'eta':[], 'led_index':42, 'state':0 }
stations[41350] = { 'name':' Oak Park (Green Line)', 'eta':[], 'led_index':43, 'state':0 }
stations[40040] = { 'name':' Quincy/Wells (Brown Orange Purple & Pink lines)', 'eta':[], 'led_index':44, 'state':0 }
stations[40390] = { 'name':' Forest Park (Blue Line)', 'eta':[], 'led_index':45, 'state':0 }
stations[41130] = { 'name':' Halsted (Orange Line)', 'eta':[], 'led_index':46, 'state':0 }
stations[40960] = { 'name':' Pulaski (Orange Line)', 'eta':[], 'led_index':47, 'state':0 }
stations[40830] = { 'name':' 18th (Pink Line)', 'eta':[], 'led_index':48, 'state':0 }
stations[40140] = { 'name':' Dempster-Skokie  (Yellow Line)', 'eta':[], 'led_index':49, 'state':0 }
stations[41320] = { 'name':' Belmont (Red Brown & Purple lines)', 'eta':[], 'led_index':50, 'state':0 }
stations[41660] = { 'name':' Lake (Red Line)', 'eta':[], 'led_index':51, 'state':0 }
stations[40910] = { 'name':' 63rd (Red Line)', 'eta':[], 'led_index':52, 'state':0 }
stations[40690] = { 'name':' Dempster (Purple Line)', 'eta':[], 'led_index':53, 'state':0 }
stations[40460] = { 'name':' Merchandise Mart (Brown & Purple lines)', 'eta':[], 'led_index':54, 'state':0 }
stations[40710] = { 'name':' Chicago (Brown & Purple lines)', 'eta':[], 'led_index':55, 'state':0 }
stations[40530] = { 'name':' Diversey (Brown & Purple lines)', 'eta':[], 'led_index':56, 'state':0 }
stations[40850] = { 'name':' Harold Washington Library-State/Van Buren (Brown Orange Purple & Pink lines)', 'eta':[], 'led_index':57, 'state':0 }
stations[41020] = { 'name':' Logan Square (Blue Line)', 'eta':[], 'led_index':58, 'state':0 }
stations[41030] = { 'name':' Polk (Pink Line)', 'eta':[], 'led_index':59, 'state':0 }
stations[41300] = { 'name':' Loyola (Red Line)', 'eta':[], 'led_index':60, 'state':0 }
stations[40310] = { 'name':' Western (Orange Line)', 'eta':[], 'led_index':61, 'state':0 }
stations[40430] = { 'name':' Clinton (Blue Line)', 'eta':[], 'led_index':62, 'state':0 }
stations[40320] = { 'name':' Division (Blue Line)', 'eta':[], 'led_index':63, 'state':0 }
stations[41510] = { 'name':' Morgan (Green & Pink lines)', 'eta':[], 'led_index':64, 'state':0 }
stations[40270] = { 'name':' Main (Purple Line)', 'eta':[], 'led_index':65, 'state':0 }
stations[41330] = { 'name':' Montrose (Blue Line)', 'eta':[], 'led_index':66, 'state':0 }
stations[40350] = { 'name':' UIC-Halsted (Blue Line)', 'eta':[], 'led_index':67, 'state':0 }
stations[40940] = { 'name':' Halsted (Green Line)', 'eta':[], 'led_index':68, 'state':0 }
stations[41480] = { 'name':' Western (Brown Line)', 'eta':[], 'led_index':69, 'state':0 }
stations[40030] = { 'name':' Pulaski (Green Line)', 'eta':[], 'led_index':70, 'state':0 }
stations[41190] = { 'name':' Jarvis (Red Line)', 'eta':[], 'led_index':71, 'state':0 }
stations[41170] = { 'name':' Garfield (Red Line)', 'eta':[], 'led_index':72, 'state':0 }
stations[40050] = { 'name':' Davis (Purple Line)', 'eta':[], 'led_index':73, 'state':0 }
stations[40750] = { 'name':' Harlem (Blue Line - OHare Branch)', 'eta':[], 'led_index':74, 'state':0 }
stations[41200] = { 'name':' Argyle (Red Line)', 'eta':[], 'led_index':75, 'state':0 }
stations[40440] = { 'name':' California (Pink Line)', 'eta':[], 'led_index':76, 'state':0 }
stations[40360] = { 'name':' Southport (Brown Line)', 'eta':[], 'led_index':77, 'state':0 }
stations[40760] = { 'name':' Granville (Red Line)', 'eta':[], 'led_index':78, 'state':0 }
stations[40480] = { 'name':' Cicero (Green Line)', 'eta':[], 'led_index':79, 'state':0 }
stations[40730] = { 'name':' Washington/Wells (Brown Orange Purple & Pink lines)', 'eta':[], 'led_index':80, 'state':0 }
stations[40580] = { 'name':' 54th/Cermak (Pink Line)', 'eta':[], 'led_index':81, 'state':0 }
stations[40650] = { 'name':' North/Clybourn (Red Line)', 'eta':[], 'led_index':82, 'state':0 }
stations[40220] = { 'name':' Western (Blue Line - Forest Park Branch)', 'eta':[], 'led_index':83, 'state':0 }
stations[40070] = { 'name':' Jackson (Blue Line)', 'eta':[], 'led_index':84, 'state':0 }
stations[41440] = { 'name':' Addison (Brown Line)', 'eta':[], 'led_index':85, 'state':0 }
stations[41670] = { 'name':' Conservatory (Green Line)', 'eta':[], 'led_index':86, 'state':0 }
stations[40790] = { 'name':' Monroe (Blue Line)', 'eta':[], 'led_index':87, 'state':0 }
stations[40180] = { 'name':' Oak Park (Blue Line)', 'eta':[], 'led_index':88, 'state':0 }
stations[40400] = { 'name':' Noyes (Purple Line)', 'eta':[], 'led_index':89, 'state':0 }
stations[41260] = { 'name':' Austin (Green Line)', 'eta':[], 'led_index':90, 'state':0 }
stations[40600] = { 'name':' Kostner (Pink Line)', 'eta':[], 'led_index':91, 'state':0 }
stations[40670] = { 'name':' Western (Blue Line - OHare Branch)', 'eta':[], 'led_index':92, 'state':0 }
stations[40100] = { 'name':' Morse (Red Line)', 'eta':[], 'led_index':93, 'state':0 }
stations[40770] = { 'name':' Lawrence (Red Line)', 'eta':[], 'led_index':94, 'state':0 }
stations[40150] = { 'name':' Pulaski (Pink Line)', 'eta':[], 'led_index':95, 'state':0 }
stations[40660] = { 'name':' Armitage (Brown & Purple lines)', 'eta':[], 'led_index':96, 'state':0 }
stations[40540] = { 'name':' Wilson (Red & Purple lines)', 'eta':[], 'led_index':97, 'state':0 }
stations[40380] = { 'name':' Clark/Lake (Blue Brown Green Orange Purple & Pink lines)', 'eta':[], 'led_index':98, 'state':0 }
stations[40160] = { 'name':' LaSalle/Van Buren (Brown Orange Purple & Pink lines)', 'eta':[], 'led_index':99, 'state':0 }
stations[40700] = { 'name':' Laramie (Green Line)', 'eta':[], 'led_index':100, 'state':0 }
stations[40240] = { 'name':' 79th (Red Line)', 'eta':[], 'led_index':101, 'state':0 }
stations[40290] = { 'name':' Ashland/63rd (Green Line)', 'eta':[], 'led_index':102, 'state':0 }
stations[40450] = { 'name':' 95th/Dan Ryan (Red Line)', 'eta':[], 'led_index':103, 'state':0 }
stations[40210] = { 'name':' Damen (Pink Line)', 'eta':[], 'led_index':104, 'state':0 }
stations[41140] = { 'name':' King Drive (Green Line)', 'eta':[], 'led_index':105, 'state':0 }
stations[41710] = { 'name':' Damen (Green Line)', 'eta':[], 'led_index':106, 'state':0 }
stations[40980] = { 'name':' Harlem (Blue Line - Forest Park Branch)', 'eta':[], 'led_index':107, 'state':0 }
stations[41270] = { 'name':' 43rd (Green Line)', 'eta':[], 'led_index':108, 'state':0 }
stations[40080] = { 'name':' Sheridan (Red Line)', 'eta':[], 'led_index':109, 'state':0 }
stations[40610] = { 'name':' Ridgeland (Green Line)', 'eta':[], 'led_index':110, 'state':0 }
stations[41070] = { 'name':' Kedzie (Green Line)', 'eta':[], 'led_index':111, 'state':0 }
stations[41430] = { 'name':' 87th (Red Line)', 'eta':[], 'led_index':112, 'state':0 }
stations[41250] = { 'name':' Central (Purple Line)', 'eta':[], 'led_index':113, 'state':0 }
stations[40880] = { 'name':' Thorndale (Red Line)', 'eta':[], 'led_index':114, 'state':0 }
stations[41680] = { 'name':' Oakton-Skokie (Yellow Line)', 'eta':[], 'led_index':115, 'state':0 }
stations[41120] = { 'name':' 35th-Bronzeville-IIT (Green Line)', 'eta':[], 'led_index':116, 'state':0 }
stations[41460] = { 'name':' Irving Park (Brown Line)', 'eta':[], 'led_index':117, 'state':0 }
stations[41220] = { 'name':' Fullerton (Red Brown & Purple lines)', 'eta':[], 'led_index':118, 'state':0 }
stations[40990] = { 'name':' 69th (Red Line)', 'eta':[], 'led_index':119, 'state':0 }
stations[41040] = { 'name':' Kedzie (Pink Line)', 'eta':[], 'led_index':120, 'state':0 }
stations[40800] = { 'name':' Sedgwick (Brown & Purple lines)', 'eta':[], 'led_index':121, 'state':0 }
stations[40060] = { 'name':' Belmont (Blue Line)', 'eta':[], 'led_index':122, 'state':0 }
stations[40840] = { 'name':' South Boulevard (Purple Line)', 'eta':[], 'led_index':123, 'state':0 }
stations[40170] = { 'name':' Ashland (Green & Pink lines)', 'eta':[], 'led_index':124, 'state':0 }
stations[40810] = { 'name':' Illinois Medical District (Blue Line)', 'eta':[], 'led_index':125, 'state':0 }
stations[41230] = { 'name':' 47th (Red Line)', 'eta':[], 'led_index':126, 'state':0 }
stations[41500] = { 'name':' Montrose (Brown Line)', 'eta':[], 'led_index':127, 'state':0 }
stations[40930] = { 'name':' Midway (Orange Line)', 'eta':[], 'led_index':128, 'state':0 }
stations[40550] = { 'name':' Irving Park (Blue Line)', 'eta':[], 'led_index':129, 'state':0 }
stations[40370] = { 'name':' Washington (Blue Line)', 'eta':[], 'led_index':130, 'state':0 }
stations[40890] = { 'name':' OHare (Blue Line)', 'eta':[], 'led_index':131, 'state':0 }
stations[40630] = { 'name':' Clark/Division (Red Line)', 'eta':[], 'led_index':132, 'state':0 }
stations[41420] = { 'name':' Addison (Red Line)', 'eta':[], 'led_index':133, 'state':0 }
stations[41290] = { 'name':' Kimball (Brown Line)', 'eta':[], 'led_index':134, 'state':0 }
stations[40300] = { 'name':' Indiana (Green Line)', 'eta':[], 'led_index':135, 'state':0 }
stations[40420] = { 'name':' Cicero (Pink Line)', 'eta':[], 'led_index':136, 'state':0 }
stations[40720] = { 'name':' Cottage Grove (Green Line)', 'eta':[], 'led_index':137, 'state':0 }
stations[41380] = { 'name':' Bryn Mawr (Red Line)', 'eta':[], 'led_index':138, 'state':0 }
stations[41450] = { 'name':' Chicago (Red Line)', 'eta':[], 'led_index':139, 'state':0 }
stations[40590] = { 'name':' Damen (Blue Line)', 'eta':[], 'led_index':140, 'state':0 }
stations[41180] = { 'name':' Kedzie (Brown Line)', 'eta':[], 'led_index':141, 'state':0 }
stations[40010] = { 'name':' Austin (Blue Line)', 'eta':[], 'led_index':142, 'state':0 }
stations[41310] = { 'name':' Paulina (Brown Line)', 'eta':[], 'led_index':143, 'state':0 }
stations[40970] = { 'name':' Cicero (Blue Line)', 'eta':[], 'led_index':144, 'state':0 }
+36 -252
View File
@@ -87,81 +87,11 @@ def start_http_server():
</html>"""
else:
# Serve the setup page for any other request
# Build list of stations
html_list = ''
for station, dict in stations.items(): # loop through all stations
html_list += f'<option value={station}>{stations[station]["name"]}</option>'
response_body = """<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Device Setup</title>
<style>
body {
font-family: sans-serif;
padding: 16px;
max-width: 400px;
margin: 0 auto;
}
h2 {
margin-top: 0;
}
label {
display: block;
margin-top: 12px;
font-weight: bold;
}
input, button {
width: 100%;
padding: 10px;
margin-top: 6px;
font-size: 16px;
box-sizing: border-box;
}
button {
margin-top: 20px;
background: #007bff;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
</style>
</head>
<body>
<h2>Device Setup</h2>
<form method="POST" action="/save">
<label>
Wi-Fi SSID
<input name="SSID" required>
</label>
<label>
Password
<input name="PASS" type="password">
</label>
<label>
CTA API Key
<input name="APIKEY">
</label>
<label>
Left LED Station:
<select name="Station">
{}
</select>
</label>
<button type="submit">Save & Connect</button>
</form>
</body>
</html>""".format(html_list)
try:
with open("portal.html") as f:
response_body = f.read()
except:
response_body = "<h1>Setup Page Not Found</h1><p>Please upload portal.html</p>"
response = (
"HTTP/1.1 200 OK\r\n"
@@ -210,10 +140,11 @@ def reconnect_wifi():
print('Retrying connection...')
sleep(2)
def init_LEDs():
def set_LEDs(stations):
# Sets up LEDs and their ports.
led = machine.Pin(15, machine.Pin.OUT)
led.off()
for station in stations:
led = machine.Pin(station['led_index'], machine.Pin.OUT)
led.value(station['state'])
# Synchronize time of RTC with NTP
last_ntp_sync = -3700 # Init as more than an hour ago
@@ -221,152 +152,7 @@ last_api_query = mktime([2000,1,1,0,0,0,0,0]) # Set last query default (will run
query_period = 120 # Query the API at most every 2 minutes
distance_on = 10 # Time from station before turning on LED
# Stations dictionary contains name, the ETA of all trains as an array, the LED index of the light and the LED state
stations = {}
stations[41090] = { 'name':' Monroe (Red Line)', 'eta':[], 'led_index':1, 'state':0 }
stations[40820] = { 'name':' Rosemont (Blue Line)', 'eta':[], 'led_index': machine.Pin(15, machine.Pin.OUT), 'state':0 }
stations[41010] = { 'name':' Rockwell (Brown Line)', 'eta':[], 'led_index':3, 'state':0 }
stations[40470] = { 'name':' Racine (Blue Line)', 'eta':[], 'led_index':4, 'state':0 }
stations[40190] = { 'name':' Sox-35th (Red Line)', 'eta':[], 'led_index':5, 'state':0 }
stations[40020] = { 'name':' Harlem/Lake (Green Line)', 'eta':[], 'led_index':6, 'state':0 }
stations[40900] = { 'name':' Howard (Red Purple & Yellow lines)', 'eta':[], 'led_index':7, 'state':0 }
stations[41160] = { 'name':' Clinton (Green & Pink lines)', 'eta':[], 'led_index':8, 'state':0 }
stations[40230] = { 'name':' Cumberland (Blue Line)', 'eta':[], 'led_index':9, 'state':0 }
stations[40560] = { 'name':' Jackson (Red Line)', 'eta':[], 'led_index':10, 'state':0 }
stations[41150] = { 'name':' Kedzie (Orange Line)', 'eta':[], 'led_index':11, 'state':0 }
stations[40780] = { 'name':' Central Park (Pink Line)', 'eta':[], 'led_index':12, 'state':0 }
stations[41080] = { 'name':' 47th (Green Line)', 'eta':[], 'led_index':13, 'state':0 }
stations[40510] = { 'name':' Garfield (Green Line)', 'eta':[], 'led_index':14, 'state':0 }
stations[41050] = { 'name':' Linden (Purple Line)', 'eta':[], 'led_index':2, 'state':0 }
stations[40120] = { 'name':' 35th/Archer (Orange Line)', 'eta':[], 'led_index':16, 'state':0 }
stations[40570] = { 'name':' California (Blue Line)', 'eta':[], 'led_index':17, 'state':0 }
stations[40260] = { 'name':' State/Lake (Brown Green Orange Pink & Purple lines)', 'eta':[], 'led_index':18, 'state':0 }
stations[40130] = { 'name':' 51st (Green Line)', 'eta':[], 'led_index':19, 'state':0 }
stations[41700] = { 'name':' Washington/Wabash (Brown Green Orange Purple & Pink lines)', 'eta':[], 'led_index':20, 'state':0 }
stations[41000] = { 'name':' Cermak-Chinatown (Red Line)', 'eta':[], 'led_index':21, 'state':0 }
stations[40340] = { 'name':' Berwyn (Red Line)', 'eta':[], 'led_index':22, 'state':0 }
stations[41690] = { 'name':' Cermak-McCormick Place (Green Line)', 'eta':[], 'led_index':23, 'state':0 }
stations[40490] = { 'name':' Grand (Blue Line)', 'eta':[], 'led_index':24, 'state':0 }
stations[41060] = { 'name':' Ashland (Orange Line)', 'eta':[], 'led_index':25, 'state':0 }
stations[40090] = { 'name':' Damen (Brown Line)', 'eta':[], 'led_index':26, 'state':0 }
stations[41280] = { 'name':' Jefferson Park (Blue Line)', 'eta':[], 'led_index':27, 'state':0 }
stations[40520] = { 'name':' Foster (Purple Line)', 'eta':[], 'led_index':28, 'state':0 }
stations[40330] = { 'name':' Grand (Red Line)', 'eta':[], 'led_index':29, 'state':0 }
stations[40280] = { 'name':' Central (Green Line)', 'eta':[], 'led_index':30, 'state':0 }
stations[40250] = { 'name':' Kedzie-Homan (Blue Line)', 'eta':[], 'led_index':31, 'state':0 }
stations[40870] = { 'name':' Francisco (Brown Line)', 'eta':[], 'led_index':32, 'state':0 }
stations[41240] = { 'name':' Addison (Blue Line)', 'eta':[], 'led_index':33, 'state':0 }
stations[40740] = { 'name':' Western (Pink Line)', 'eta':[], 'led_index':34, 'state':0 }
stations[41360] = { 'name':' California (Green Line)', 'eta':[], 'led_index':35, 'state':0 }
stations[41400] = { 'name':' Roosevelt (Red Orange & Green lines)', 'eta':[], 'led_index':36, 'state':0 }
stations[41410] = { 'name':' Chicago (Blue Line)', 'eta':[], 'led_index':37, 'state':0 }
stations[40680] = { 'name':' Adams/Wabash (Brown Green Orange Pink & Purple lines)', 'eta':[], 'led_index':38, 'state':0 }
stations[40920] = { 'name':' Pulaski (Blue Line)', 'eta':[], 'led_index':39, 'state':0 }
stations[41210] = { 'name':' Wellington (Brown & Purple lines)', 'eta':[], 'led_index':40, 'state':0 }
stations[41340] = { 'name':' LaSalle (Blue Line)', 'eta':[], 'led_index':41, 'state':0 }
stations[41490] = { 'name':' Harrison (Red Line)', 'eta':[], 'led_index':42, 'state':0 }
stations[41350] = { 'name':' Oak Park (Green Line)', 'eta':[], 'led_index':43, 'state':0 }
stations[40040] = { 'name':' Quincy/Wells (Brown Orange Purple & Pink lines)', 'eta':[], 'led_index':44, 'state':0 }
stations[40390] = { 'name':' Forest Park (Blue Line)', 'eta':[], 'led_index':45, 'state':0 }
stations[41130] = { 'name':' Halsted (Orange Line)', 'eta':[], 'led_index':46, 'state':0 }
stations[40960] = { 'name':' Pulaski (Orange Line)', 'eta':[], 'led_index':47, 'state':0 }
stations[40830] = { 'name':' 18th (Pink Line)', 'eta':[], 'led_index':48, 'state':0 }
stations[40140] = { 'name':' Dempster-Skokie  (Yellow Line)', 'eta':[], 'led_index':49, 'state':0 }
stations[41320] = { 'name':' Belmont (Red Brown & Purple lines)', 'eta':[], 'led_index':50, 'state':0 }
stations[41660] = { 'name':' Lake (Red Line)', 'eta':[], 'led_index':51, 'state':0 }
stations[40910] = { 'name':' 63rd (Red Line)', 'eta':[], 'led_index':52, 'state':0 }
stations[40690] = { 'name':' Dempster (Purple Line)', 'eta':[], 'led_index':53, 'state':0 }
stations[40460] = { 'name':' Merchandise Mart (Brown & Purple lines)', 'eta':[], 'led_index':54, 'state':0 }
stations[40710] = { 'name':' Chicago (Brown & Purple lines)', 'eta':[], 'led_index':55, 'state':0 }
stations[40530] = { 'name':' Diversey (Brown & Purple lines)', 'eta':[], 'led_index':56, 'state':0 }
stations[40850] = { 'name':' Harold Washington Library-State/Van Buren (Brown Orange Purple & Pink lines)', 'eta':[], 'led_index':57, 'state':0 }
stations[41020] = { 'name':' Logan Square (Blue Line)', 'eta':[], 'led_index':58, 'state':0 }
stations[41030] = { 'name':' Polk (Pink Line)', 'eta':[], 'led_index':59, 'state':0 }
stations[41300] = { 'name':' Loyola (Red Line)', 'eta':[], 'led_index':60, 'state':0 }
stations[40310] = { 'name':' Western (Orange Line)', 'eta':[], 'led_index':61, 'state':0 }
stations[40430] = { 'name':' Clinton (Blue Line)', 'eta':[], 'led_index':62, 'state':0 }
stations[40320] = { 'name':' Division (Blue Line)', 'eta':[], 'led_index':63, 'state':0 }
stations[41510] = { 'name':' Morgan (Green & Pink lines)', 'eta':[], 'led_index':64, 'state':0 }
stations[40270] = { 'name':' Main (Purple Line)', 'eta':[], 'led_index':65, 'state':0 }
stations[41330] = { 'name':' Montrose (Blue Line)', 'eta':[], 'led_index':66, 'state':0 }
stations[40350] = { 'name':' UIC-Halsted (Blue Line)', 'eta':[], 'led_index':67, 'state':0 }
stations[40940] = { 'name':' Halsted (Green Line)', 'eta':[], 'led_index':68, 'state':0 }
stations[41480] = { 'name':' Western (Brown Line)', 'eta':[], 'led_index':69, 'state':0 }
stations[40030] = { 'name':' Pulaski (Green Line)', 'eta':[], 'led_index':70, 'state':0 }
stations[41190] = { 'name':' Jarvis (Red Line)', 'eta':[], 'led_index':71, 'state':0 }
stations[41170] = { 'name':' Garfield (Red Line)', 'eta':[], 'led_index':72, 'state':0 }
stations[40050] = { 'name':' Davis (Purple Line)', 'eta':[], 'led_index':73, 'state':0 }
stations[40750] = { 'name':' Harlem (Blue Line - OHare Branch)', 'eta':[], 'led_index':74, 'state':0 }
stations[41200] = { 'name':' Argyle (Red Line)', 'eta':[], 'led_index':75, 'state':0 }
stations[40440] = { 'name':' California (Pink Line)', 'eta':[], 'led_index':76, 'state':0 }
stations[40360] = { 'name':' Southport (Brown Line)', 'eta':[], 'led_index':77, 'state':0 }
stations[40760] = { 'name':' Granville (Red Line)', 'eta':[], 'led_index':78, 'state':0 }
stations[40480] = { 'name':' Cicero (Green Line)', 'eta':[], 'led_index':79, 'state':0 }
stations[40730] = { 'name':' Washington/Wells (Brown Orange Purple & Pink lines)', 'eta':[], 'led_index':80, 'state':0 }
stations[40580] = { 'name':' 54th/Cermak (Pink Line)', 'eta':[], 'led_index':81, 'state':0 }
stations[40650] = { 'name':' North/Clybourn (Red Line)', 'eta':[], 'led_index':82, 'state':0 }
stations[40220] = { 'name':' Western (Blue Line - Forest Park Branch)', 'eta':[], 'led_index':83, 'state':0 }
stations[40070] = { 'name':' Jackson (Blue Line)', 'eta':[], 'led_index':84, 'state':0 }
stations[41440] = { 'name':' Addison (Brown Line)', 'eta':[], 'led_index':85, 'state':0 }
stations[41670] = { 'name':' Conservatory (Green Line)', 'eta':[], 'led_index':86, 'state':0 }
stations[40790] = { 'name':' Monroe (Blue Line)', 'eta':[], 'led_index':87, 'state':0 }
stations[40180] = { 'name':' Oak Park (Blue Line)', 'eta':[], 'led_index':88, 'state':0 }
stations[40400] = { 'name':' Noyes (Purple Line)', 'eta':[], 'led_index':89, 'state':0 }
stations[41260] = { 'name':' Austin (Green Line)', 'eta':[], 'led_index':90, 'state':0 }
stations[40600] = { 'name':' Kostner (Pink Line)', 'eta':[], 'led_index':91, 'state':0 }
stations[40670] = { 'name':' Western (Blue Line - OHare Branch)', 'eta':[], 'led_index':92, 'state':0 }
stations[40100] = { 'name':' Morse (Red Line)', 'eta':[], 'led_index':93, 'state':0 }
stations[40770] = { 'name':' Lawrence (Red Line)', 'eta':[], 'led_index':94, 'state':0 }
stations[40150] = { 'name':' Pulaski (Pink Line)', 'eta':[], 'led_index':95, 'state':0 }
stations[40660] = { 'name':' Armitage (Brown & Purple lines)', 'eta':[], 'led_index':96, 'state':0 }
stations[40540] = { 'name':' Wilson (Red & Purple lines)', 'eta':[], 'led_index':97, 'state':0 }
stations[40380] = { 'name':' Clark/Lake (Blue Brown Green Orange Purple & Pink lines)', 'eta':[], 'led_index':98, 'state':0 }
stations[40160] = { 'name':' LaSalle/Van Buren (Brown Orange Purple & Pink lines)', 'eta':[], 'led_index':99, 'state':0 }
stations[40700] = { 'name':' Laramie (Green Line)', 'eta':[], 'led_index':100, 'state':0 }
stations[40240] = { 'name':' 79th (Red Line)', 'eta':[], 'led_index':101, 'state':0 }
stations[40290] = { 'name':' Ashland/63rd (Green Line)', 'eta':[], 'led_index':102, 'state':0 }
stations[40450] = { 'name':' 95th/Dan Ryan (Red Line)', 'eta':[], 'led_index':103, 'state':0 }
stations[40210] = { 'name':' Damen (Pink Line)', 'eta':[], 'led_index':104, 'state':0 }
stations[41140] = { 'name':' King Drive (Green Line)', 'eta':[], 'led_index':105, 'state':0 }
stations[41710] = { 'name':' Damen (Green Line)', 'eta':[], 'led_index':106, 'state':0 }
stations[40980] = { 'name':' Harlem (Blue Line - Forest Park Branch)', 'eta':[], 'led_index':107, 'state':0 }
stations[41270] = { 'name':' 43rd (Green Line)', 'eta':[], 'led_index':108, 'state':0 }
stations[40080] = { 'name':' Sheridan (Red Line)', 'eta':[], 'led_index':109, 'state':0 }
stations[40610] = { 'name':' Ridgeland (Green Line)', 'eta':[], 'led_index':110, 'state':0 }
stations[41070] = { 'name':' Kedzie (Green Line)', 'eta':[], 'led_index':111, 'state':0 }
stations[41430] = { 'name':' 87th (Red Line)', 'eta':[], 'led_index':112, 'state':0 }
stations[41250] = { 'name':' Central (Purple Line)', 'eta':[], 'led_index':113, 'state':0 }
stations[40880] = { 'name':' Thorndale (Red Line)', 'eta':[], 'led_index':114, 'state':0 }
stations[41680] = { 'name':' Oakton-Skokie (Yellow Line)', 'eta':[], 'led_index':115, 'state':0 }
stations[41120] = { 'name':' 35th-Bronzeville-IIT (Green Line)', 'eta':[], 'led_index':116, 'state':0 }
stations[41460] = { 'name':' Irving Park (Brown Line)', 'eta':[], 'led_index':117, 'state':0 }
stations[41220] = { 'name':' Fullerton (Red Brown & Purple lines)', 'eta':[], 'led_index':118, 'state':0 }
stations[40990] = { 'name':' 69th (Red Line)', 'eta':[], 'led_index':119, 'state':0 }
stations[41040] = { 'name':' Kedzie (Pink Line)', 'eta':[], 'led_index':120, 'state':0 }
stations[40800] = { 'name':' Sedgwick (Brown & Purple lines)', 'eta':[], 'led_index':121, 'state':0 }
stations[40060] = { 'name':' Belmont (Blue Line)', 'eta':[], 'led_index':122, 'state':0 }
stations[40840] = { 'name':' South Boulevard (Purple Line)', 'eta':[], 'led_index':123, 'state':0 }
stations[40170] = { 'name':' Ashland (Green & Pink lines)', 'eta':[], 'led_index':124, 'state':0 }
stations[40810] = { 'name':' Illinois Medical District (Blue Line)', 'eta':[], 'led_index':125, 'state':0 }
stations[41230] = { 'name':' 47th (Red Line)', 'eta':[], 'led_index':126, 'state':0 }
stations[41500] = { 'name':' Montrose (Brown Line)', 'eta':[], 'led_index':127, 'state':0 }
stations[40930] = { 'name':' Midway (Orange Line)', 'eta':[], 'led_index':128, 'state':0 }
stations[40550] = { 'name':' Irving Park (Blue Line)', 'eta':[], 'led_index':129, 'state':0 }
stations[40370] = { 'name':' Washington (Blue Line)', 'eta':[], 'led_index':130, 'state':0 }
stations[40890] = { 'name':' OHare (Blue Line)', 'eta':[], 'led_index':131, 'state':0 }
stations[40630] = { 'name':' Clark/Division (Red Line)', 'eta':[], 'led_index':132, 'state':0 }
stations[41420] = { 'name':' Addison (Red Line)', 'eta':[], 'led_index':133, 'state':0 }
stations[41290] = { 'name':' Kimball (Brown Line)', 'eta':[], 'led_index':134, 'state':0 }
stations[40300] = { 'name':' Indiana (Green Line)', 'eta':[], 'led_index':135, 'state':0 }
stations[40420] = { 'name':' Cicero (Pink Line)', 'eta':[], 'led_index':136, 'state':0 }
stations[40720] = { 'name':' Cottage Grove (Green Line)', 'eta':[], 'led_index':137, 'state':0 }
stations[41380] = { 'name':' Bryn Mawr (Red Line)', 'eta':[], 'led_index':138, 'state':0 }
stations[41450] = { 'name':' Chicago (Red Line)', 'eta':[], 'led_index':139, 'state':0 }
stations[40590] = { 'name':' Damen (Blue Line)', 'eta':[], 'led_index':140, 'state':0 }
stations[41180] = { 'name':' Kedzie (Brown Line)', 'eta':[], 'led_index':141, 'state':0 }
stations[40010] = { 'name':' Austin (Blue Line)', 'eta':[], 'led_index':142, 'state':0 }
stations[41310] = { 'name':' Paulina (Brown Line)', 'eta':[], 'led_index':143, 'state':0 }
stations[40970] = { 'name':' Cicero (Blue Line)', 'eta':[], 'led_index':144, 'state':0 }
# Check if already configured and load config for Wifi, API Key etc.
try:
@@ -375,6 +161,11 @@ try:
APIKEY = config.APIKEY
SSID = config.SSID
PASS = config.PASS
# Won't scale well for infinite LEDs
stations["L"] = { 'id':config.LStation, 'eta':[], 'led_index':15, 'state':0 }
stations["R"] = { 'id':config.RStation, 'eta':[], 'led_index':16, 'state':0 }
# Function sets up LEDs.
set_LEDs()
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
reconnect_wifi()
@@ -389,11 +180,6 @@ except:
while(True):
sleep(5)
# Function sets up all LEDs.
init_LEDs()
while(True):
# Synchronise NTP time if hasn't been done in 1 hour
if (time() - last_ntp_sync) > 3600:
@@ -408,41 +194,39 @@ while(True):
# Have we queried API in the query_period seconds?
if (time() - last_api_query) > query_period:
# Query updated API
trains = (requests.get("https://lapi.transitchicago.com/api/1.0/ttpositions.aspx?key="+APIKEY+"&rt=Blue&outputType=JSON")).json()['ctatt']
#trains = (requests.get("https://lapi.transitchicago.com/api/1.0/ttpositions.aspx?key="+APIKEY+"&rt=Blue&outputType=JSON")).json()['ctatt']
# Query all stations
for station,dict in stations.item():
trains_s = (requests.get(f"https://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key={APIKEY}&mapid={dict['id']}outputType=JSON")).json()['ctatt']
# Timestamps are served in local Chicago time, convert to GMT for simplicity on this side.
print(f"Time of poll is: "+str(gmtime(time_from_iso(trains['tmst'])+(5*60*60))))
# Timestamps are served in local Chicago time, convert to GMT for simplicity on this side.
#print(f"Time of poll is: "+str(gmtime(time_from_iso(trains_s['tmst'])+(5*60*60))))
# Loop through all trains and update matching stations
for train in trains['route'][0]['train']:
nextStation = int(train['nextStaId'])
eta_time = time_from_iso(train['arrT'])+(5*60*60)
# Loop through all trains and update matching stations
for train in trains_s['eta']:
eta_time = time_from_iso(train['arrT'])+(5*60*60)
# Append the ETA, we rely on the station loop to remove old trains
stations[nextStation]['eta'].append(eta_time)
# Append the ETA, we rely on the station loop to remove old trains
stations[station]['eta'].append(eta_time)
last_api_query = time() # uptime polling window
# Process the ETA for each station
for station, dict in stations.items(): # loop through all stations
if station == 40820: # Our test station for onboard LED
# Set LED state tracker to 0, if no trains, it'll stay 0.
stations[station]['state'] = 0
for index, eta in enumerate(dict['eta']): # multiple trains. Enumerate is used so we have the index to update the dict itself.
time_from_now = eta - time()
# Set LED state tracker to 0, if no trains, it'll stay 0.
stations[station]['state'] = 0
for index, eta in enumerate(dict['eta']): # multiple trains. Enumerate is used so we have the index to update the dict itself.
time_from_now = eta - time()
print('Train will arrive at'+dict['name']+' in '+ str(time_from_now) + ' seconds')
if time_from_now < distance_on:
stations[station]['state'] = 1
print('Train will arrive at'+dict['name']+' in '+ str(time_from_now) + ' seconds')
if time_from_now < distance_on:
stations[station]['state'] = 1
if time_from_now < -distance_on: # Remove old trains
stations[station]['eta'].pop(index)
if time_from_now < -distance_on: # Remove old trains
stations[station]['eta'].pop(index)
# Set Station LED state
stations[station]['led_index'].value(stations[station]['state'])
# Set Station LED state
set_LEDs()
sleep(1)
+63 -60
View File
@@ -1,69 +1,72 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Device Setup</title>
<style>
body {
font-family: sans-serif;
padding: 16px;
max-width: 400px;
margin: 0 auto;
}
h2 {
margin-top: 0;
}
label {
display: block;
margin-top: 12px;
font-weight: bold;
}
input, button {
width: 100%;
padding: 10px;
margin-top: 6px;
font-size: 16px;
box-sizing: border-box;
}
button {
margin-top: 20px;
background: #007bff;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
</style>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Device Setup</title>
<style>
body {
font-family: sans-serif;
padding: 16px;
max-width: 400px;
margin: 0 auto;
}
h2 {
margin-top: 0;
}
label {
display: block;
margin-top: 12px;
font-weight: bold;
}
input, button {
width: 100%;
padding: 10px;
margin-top: 6px;
font-size: 16px;
box-sizing: border-box;
}
button {
margin-top: 20px;
background: #007bff;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
</style>
</head>
<body>
<h2>Device Setup</h2>
<h2>Device Setup</h2>
<form method="POST" action="/save">
<label>
Wi-Fi SSID
<input name="SSID" required>
</label>
<form method="POST" action="/save">
<label>
Wi-Fi SSID
<input name="SSID" required>
</label>
<label>
Password
<input name="PASS" type="password">
</label>
<label>
CTA API Key
<input name="APIKEY">
</label>
<label>
Left LED Station:
<select name="LStation"><option value=41090>Monroe (Red Line)</option><option value=41010>Rockwell (Brown Line)</option><option value=40470>Racine (Blue Line)</option><option value=40190>Sox-35th (Red Line)</option><option value=40020>Harlem/Lake (Green Line)</option><option value=40900>Howard (Red Purple & Yellow lines)</option><option value=41160>Clinton (Green & Pink lines)</option><option value=40230>Cumberland (Blue Line)</option><option value=40560>Jackson (Red Line)</option><option value=41150>Kedzie (Orange Line)</option><option value=40780>Central Park (Pink Line)</option><option value=41080>47th (Green Line)</option><option value=40510>Garfield (Green Line)</option><option value=41050>Linden (Purple Line)</option><option value=40120>35th/Archer (Orange Line)</option><option value=40570>California (Blue Line)</option><option value=40260>State/Lake (Brown Green Orange Pink & Purple lines)</option><option value=40130>51st (Green Line)</option><option value=41700>Washington/Wabash (Brown Green Orange Purple & Pink lines)</option><option value=41000>Cermak-Chinatown (Red Line)</option><option value=40340>Berwyn (Red Line)</option><option value=41690>Cermak-McCormick Place (Green Line)</option><option value=40490>Grand (Blue Line)</option><option value=41060>Ashland (Orange Line)</option><option value=40090>Damen (Brown Line)</option><option value=41280>Jefferson Park (Blue Line)</option><option value=40520>Foster (Purple Line)</option><option value=40330>Grand (Red Line)</option><option value=40280>Central (Green Line)</option><option value=40250>Kedzie-Homan (Blue Line)</option><option value=40870>Francisco (Brown Line)</option><option value=41240>Addison (Blue Line)</option><option value=40740>Western (Pink Line)</option><option value=41360>California (Green Line)</option><option value=41400>Roosevelt (Red Orange & Green lines)</option><option value=41410>Chicago (Blue Line)</option><option value=40680>Adams/Wabash (Brown Green Orange Pink & Purple lines)</option><option value=40920>Pulaski (Blue Line)</option><option value=41210>Wellington (Brown & Purple lines)</option><option value=41340>LaSalle (Blue Line)</option><option value=41490>Harrison (Red Line)</option><option value=41350>Oak Park (Green Line)</option><option value=40040>Quincy/Wells (Brown Orange Purple & Pink lines)</option><option value=40390>Forest Park (Blue Line)</option><option value=41130>Halsted (Orange Line)</option><option value=40960>Pulaski (Orange Line)</option><option value=40830>18th (Pink Line)</option><option value=40140>Dempster-Skokie \xa0(Yellow Line)</option><option value=41320>Belmont (Red Brown & Purple lines)</option><option value=41660>Lake (Red Line)</option><option value=40910>63rd (Red Line)</option><option value=40690>Dempster (Purple Line)</option><option value=40460>Merchandise Mart (Brown & Purple lines)</option><option value=40710>Chicago (Brown & Purple lines)</option><option value=40530>Diversey (Brown & Purple lines)</option><option value=40850>Harold Washington Library-State/Van Buren (Brown Orange Purple & Pink lines)</option><option value=41020>Logan Square (Blue Line)</option><option value=41030>Polk (Pink Line)</option><option value=41300>Loyola (Red Line)</option><option value=40310>Western (Orange Line)</option><option value=40430>Clinton (Blue Line)</option><option value=40320>Division (Blue Line)</option><option value=41510>Morgan (Green & Pink lines)</option><option value=40270>Main (Purple Line)</option><option value=41330>Montrose (Blue Line)</option><option value=40350>UIC-Halsted (Blue Line)</option><option value=40940>Halsted (Green Line)</option><option value=41480>Western (Brown Line)</option><option value=40030>Pulaski (Green Line)</option><option value=41190>Jarvis (Red Line)</option><option value=41170>Garfield (Red Line)</option><option value=40050>Davis (Purple Line)</option><option value=40750>Harlem (Blue Line - OHare Branch)</option><option value=41200>Argyle (Red Line)</option><option value=40440>California (Pink Line)</option><option value=40360>Southport (Brown Line)</option><option value=40760>Granville (Red Line)</option><option value=40480>Cicero (Green Line)</option><option value=40730>Washington/Wells (Brown Orange Purple & Pink lines)</option><option value=40580>54th/Cermak (Pink Line)</option><option value=40650>North/Clybourn (Red Line)</option><option value=40220>Western (Blue Line - Forest Park Branch)</option><option value=40070>Jackson (Blue Line)</option><option value=41440>Addison (Brown Line)</option><option value=41670>Conservatory (Green Line)</option><option value=40790>Monroe (Blue Line)</option><option value=40180>Oak Park (Blue Line)</option><option value=40400>Noyes (Purple Line)</option><option value=41260>Austin (Green Line)</option><option value=40600>Kostner (Pink Line)</option><option value=40670>Western (Blue Line - OHare Branch)</option><option value=40100>Morse (Red Line)</option><option value=40770>Lawrence (Red Line)</option><optiLine truncated
</label>
<label>
Password
<input name="PASS" type="password">
</label>
Right LED Station:
<select name="RStation"><option value=41090>Monroe (Red Line)</option><option value=41010>Rockwell (Brown Line)</option><option value=40470>Racine (Blue Line)</option><option value=40190>Sox-35th (Red Line)</option><option value=40020>Harlem/Lake (Green Line)</option><option value=40900>Howard (Red Purple & Yellow lines)</option><option value=41160>Clinton (Green & Pink lines)</option><option value=40230>Cumberland (Blue Line)</option><option value=40560>Jackson (Red Line)</option><option value=41150>Kedzie (Orange Line)</option><option value=40780>Central Park (Pink Line)</option><option value=41080>47th (Green Line)</option><option value=40510>Garfield (Green Line)</option><option value=41050>Linden (Purple Line)</option><option value=40120>35th/Archer (Orange Line)</option><option value=40570>California (Blue Line)</option><option value=40260>State/Lake (Brown Green Orange Pink & Purple lines)</option><option value=40130>51st (Green Line)</option><option value=41700>Washington/Wabash (Brown Green Orange Purple & Pink lines)</option><option value=41000>Cermak-Chinatown (Red Line)</option><option value=40340>Berwyn (Red Line)</option><option value=41690>Cermak-McCormick Place (Green Line)</option><option value=40490>Grand (Blue Line)</option><option value=41060>Ashland (Orange Line)</option><option value=40090>Damen (Brown Line)</option><option value=41280>Jefferson Park (Blue Line)</option><option value=40520>Foster (Purple Line)</option><option value=40330>Grand (Red Line)</option><option value=40280>Central (Green Line)</option><option value=40250>Kedzie-Homan (Blue Line)</option><option value=40870>Francisco (Brown Line)</option><option value=41240>Addison (Blue Line)</option><option value=40740>Western (Pink Line)</option><option value=41360>California (Green Line)</option><option value=41400>Roosevelt (Red Orange & Green lines)</option><option value=41410>Chicago (Blue Line)</option><option value=40680>Adams/Wabash (Brown Green Orange Pink & Purple lines)</option><option value=40920>Pulaski (Blue Line)</option><option value=41210>Wellington (Brown & Purple lines)</option><option value=41340>LaSalle (Blue Line)</option><option value=41490>Harrison (Red Line)</option><option value=41350>Oak Park (Green Line)</option><option value=40040>Quincy/Wells (Brown Orange Purple & Pink lines)</option><option value=40390>Forest Park (Blue Line)</option><option value=41130>Halsted (Orange Line)</option><option value=40960>Pulaski (Orange Line)</option><option value=40830>18th (Pink Line)</option><option value=40140>Dempster-Skokie \xa0(Yellow Line)</option><option value=41320>Belmont (Red Brown & Purple lines)</option><option value=41660>Lake (Red Line)</option><option value=40910>63rd (Red Line)</option><option value=40690>Dempster (Purple Line)</option><option value=40460>Merchandise Mart (Brown & Purple lines)</option><option value=40710>Chicago (Brown & Purple lines)</option><option value=40530>Diversey (Brown & Purple lines)</option><option value=40850>Harold Washington Library-State/Van Buren (Brown Orange Purple & Pink lines)</option><option value=41020>Logan Square (Blue Line)</option><option value=41030>Polk (Pink Line)</option><option value=41300>Loyola (Red Line)</option><option value=40310>Western (Orange Line)</option><option value=40430>Clinton (Blue Line)</option><option value=40320>Division (Blue Line)</option><option value=41510>Morgan (Green & Pink lines)</option><option value=40270>Main (Purple Line)</option><option value=41330>Montrose (Blue Line)</option><option value=40350>UIC-Halsted (Blue Line)</option><option value=40940>Halsted (Green Line)</option><option value=41480>Western (Brown Line)</option><option value=40030>Pulaski (Green Line)</option><option value=41190>Jarvis (Red Line)</option><option value=41170>Garfield (Red Line)</option><option value=40050>Davis (Purple Line)</option><option value=40750>Harlem (Blue Line - OHare Branch)</option><option value=41200>Argyle (Red Line)</option><option value=40440>California (Pink Line)</option><option value=40360>Southport (Brown Line)</option><option value=40760>Granville (Red Line)</option><option value=40480>Cicero (Green Line)</option><option value=40730>Washington/Wells (Brown Orange Purple & Pink lines)</option><option value=40580>54th/Cermak (Pink Line)</option><option value=40650>North/Clybourn (Red Line)</option><option value=40220>Western (Blue Line - Forest Park Branch)</option><option value=40070>Jackson (Blue Line)</option><option value=41440>Addison (Brown Line)</option><option value=41670>Conservatory (Green Line)</option><option value=40790>Monroe (Blue Line)</option><option value=40180>Oak Park (Blue Line)</option><option value=40400>Noyes (Purple Line)</option><option value=41260>Austin (Green Line)</option><option value=40600>Kostner (Pink Line)</option><option value=40670>Western (Blue Line - OHare Branch)</option><option value=40100>Morse (Red Line)</option><option value=40770>Lawrence (Red Line)</option><optiLine truncated
</label>
<label>
CTA API Key
<input name="APIKEY">
</label>
<label>
Left LED Station:
<select name="Station">
<option value="40820">Rosemont</option>
</select>
</label>
<button type="submit">Save & Connect</button>
</form>
<button type="submit">Save & Connect</button>
</form>
</body>
</html>
</html>