{"id":49272070,"url":"https://github.com/alopes/esp32-tfl-bus-led","last_synced_at":"2026-04-25T14:10:51.022Z","repository":{"id":342100780,"uuid":"1172833053","full_name":"alopes/esp32-tfl-bus-led","owner":"alopes","description":"ESP32-S3 RGB LED that shows how soon your next bus arrives using the TfL API","archived":false,"fork":false,"pushed_at":"2026-03-22T20:27:33.000Z","size":230,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-23T10:56:14.156Z","etag":null,"topics":["arduino","esp32","esp32-s3","iot","london-bus","neopixel","platformio","tfl"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alopes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-04T18:24:55.000Z","updated_at":"2026-03-22T20:27:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/alopes/esp32-tfl-bus-led","commit_stats":null,"previous_names":["alopes/esp32-tfl-bus-led"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/alopes/esp32-tfl-bus-led","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alopes%2Fesp32-tfl-bus-led","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alopes%2Fesp32-tfl-bus-led/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alopes%2Fesp32-tfl-bus-led/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alopes%2Fesp32-tfl-bus-led/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alopes","download_url":"https://codeload.github.com/alopes/esp32-tfl-bus-led/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alopes%2Fesp32-tfl-bus-led/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32264566,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T09:15:33.318Z","status":"ssl_error","status_checked_at":"2026-04-25T09:15:31.997Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","esp32","esp32-s3","iot","london-bus","neopixel","platformio","tfl"],"created_at":"2026-04-25T14:10:50.435Z","updated_at":"2026-04-25T14:10:51.016Z","avatar_url":"https://github.com/alopes.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ESP32 TfL Bus Indicator\n\n![ESP32 TfL Bus Indicator](esp32-tfl-bus-indicator.jpg)\n\nReal-time bus departure board powered by an ESP32-S3 with a 2.8\" TFT touchscreen and RGB LED. Polls the [TfL Unified API](https://api.tfl.gov.uk/) every 30 seconds and displays up to 7 upcoming arrivals with colour-coded countdown timers.\n\n## Features\n\n- **Live departures** — line number, destination, and minutes until arrival, updated every second between API polls\n- **Colour-coded urgency** — both the TFT colour bars and onboard RGB LED reflect how soon the next bus arrives\n- **Touchscreen navigation** — tap the settings cog to view device info (QR code, hostname, config); tap the back arrow to return\n- **Display themes** — three selectable themes (Classic, Dark, Light) that apply instantly\n- **Web settings page** — configure Wi-Fi, stop ID, tracked lines, display theme, and status bar visibility from any browser\n- **API key authentication** — all write endpoints require an API key; the key is auto-generated and shown during initial setup\n- **QR code access** — the device info screen shows a QR code linking directly to the settings page with the API key pre-filled\n- **NVS persistence** — all settings survive reboots\n- **Captive portal provisioning** — first-boot Wi-Fi setup via a hotspot with automatic portal redirect\n\n## LED Colours\n\n| Nearest Bus | LED |\n|---|---|\n| \u003e= 15 min or no data | Off |\n| 10–14 min | Blue |\n| 5–9 min | Yellow |\n| 2–4 min | Red |\n| 0–1 min | Flashing red |\n\n## TFT Display\n\nThe ILI9341 2.8\" TFT (240×320) has two screens:\n\n**Departures** — up to 7 rows showing line, destination, and countdown minutes with colour-coded urgency bars. An optional status bar at the bottom shows Wi-Fi status and time since last update.\n\n**Device Info** — QR code linking to the settings page, plus hostname, stop ID, tracked lines, and API key.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"display-preview.svg\" alt=\"Display preview\" width=\"280\"\u003e\n\u003c/p\u003e\n\n### Display Themes\n\n| Theme | Description |\n|---|---|\n| Classic | Dark background with blue headers |\n| Dark | Pure black background with grey headers, inverted QR code |\n| Light | White background with blue headers, dark text |\n\nThemes can be changed from the web settings page and take effect immediately.\n\n### Wiring\n\n| ILI9341 Pin | ESP32-S3 GPIO |\n|---|---|\n| CS | GPIO 10 |\n| RST | GPIO 9 |\n| DC | GPIO 8 |\n| MOSI | GPIO 11 |\n| SCK | GPIO 12 |\n| LED | 3V3 |\n| VCC | 3V3 |\n| GND | GND |\n\n| XPT2046 Touch Pin | ESP32-S3 GPIO |\n|---|---|\n| T_CS | GPIO 15 |\n| T_CLK | GPIO 18 |\n| T_DIN | GPIO 16 |\n| T_DO | GPIO 17 |\n\n## How It Works\n\nThe device connects to Wi-Fi and polls the TfL Unified API every 30 seconds for live arrivals at your configured stop. It filters the response to only the bus lines you're tracking, collects up to 8 arrivals sorted by time, and displays them on the TFT screen. The nearest arrival also drives the LED colour (see table above). Between polls, displayed minutes count down in real time. Serial output logs each update with the line, destination, and colour.\n\nOnce connected, the device runs a web server with a settings page for runtime configuration. All changes (Wi-Fi, tracking, display) are applied immediately and persisted to NVS.\n\n## Hardware\n\n- [ESP32-S3-DevKitC-1](https://amzn.to/40KIAMw) (any variant with onboard WS2812 RGB LED on GPIO48)\n- [ILI9341 2.8\" SPI TFT display with XPT2046 touch](https://amzn.to/3YQ4Lkw) (240×320, 4-wire SPI)\n- USB-C cable for power and flashing\n\n## Setup\n\n1. Install [PlatformIO CLI](https://docs.platformio.org/en/latest/core/installation.html)\n\n2. Build and flash:\n   ```bash\n   pio run -t upload\n   ```\n\n3. The device starts a Wi-Fi hotspot called **BusIndicator-XXYYZZ** (the LED pulses blue). Connect to it with your phone or laptop — a setup page opens automatically.\n\n   \u003cimg src=\"setup.jpg\" alt=\"Setup portal\" width=\"300\"\u003e\n\n4. Enter your Wi-Fi credentials, TfL stop ID, and bus lines. Save the API key shown on the setup page — you will need it to access settings later. The device saves the config, restarts, and connects to your network.\n\n5. Once connected, tap the settings cog on the TFT or scan the QR code on the device info screen to open the web settings page.\n\nTo find your stop's NaptanId, search the [TfL API](https://api.tfl.gov.uk/) at `https://api.tfl.gov.uk/StopPoint/Search/{query}` and use the `naptanId` field. Line names are case-sensitive and must match the `lineName` field exactly (e.g. `73,390,N73`).\n\n### Compile-time credentials (optional)\n\nIf you prefer to bake credentials into the firmware instead of using the setup portal, copy the example and fill in your values:\n\n```bash\ncp secrets.example.ini secrets.ini\n# Edit secrets.ini with your Wi-Fi credentials, stop ID, and bus lines\n```\n\n## HTTP API\n\nAll POST endpoints require an `X-Api-Key` header. The API key is auto-generated on first boot and shown on the provisioning page.\n\n| Method | Endpoint | Description |\n|---|---|---|\n| GET | `/` | Settings page (HTML) |\n| GET | `/scan` | Scan for Wi-Fi networks |\n| GET | `/config/device` | Device name, Wi-Fi SSID |\n| POST | `/config/device` | Update device name, Wi-Fi credentials |\n| GET | `/config/tracking` | Stop ID, tracked lines |\n| POST | `/config/tracking` | Update stop ID, tracked lines |\n| GET | `/config/display` | Theme, status bar visibility |\n| POST | `/config/display` | Update theme, status bar visibility |\n| GET | `/status` | Wi-Fi status, IP address, uptime |\n\n## Factory Reset\n\nHold the **BOOT** button for 5 seconds (LED flashes white while held). The device clears its Wi-Fi credentials and API key, restarts, and re-enters the setup portal. A new API key is generated during setup. Stop ID, tracked lines, and display settings are preserved.\n\n## Configuration\n\nAll settings (Wi-Fi, stop ID, tracked lines, display theme, status bar) can be changed at runtime via the web settings page or HTTP API without reflashing. Thresholds, LED settings, pin assignments, and poll interval can be adjusted in `include/config.h`.\n\n## Project Structure\n\n```\n├── src/main.cpp           — application logic (single file)\n├── include/config.h       — pins, thresholds, LED, poll interval\n├── secrets.ini            — Wi-Fi and TfL credentials (not committed)\n├── secrets.example.ini    — template for secrets.ini\n└── platformio.ini         — PlatformIO build config and library deps\n```\n\n## Troubleshooting\n\n- **LED pulses blue on boot** — the device has no Wi-Fi credentials and is in setup mode. Connect to the BusIndicator hotspot to configure it.\n- **LED stays off** — check that your stop ID is correct and the line names match the TfL API response.\n- **Wi-Fi connection failed** — if the device cannot connect within 10 seconds, it falls back to setup mode automatically.\n- **\"No tracked departures\" on screen** — line names must match the TfL `lineName` field exactly (case-sensitive). Open `https://api.tfl.gov.uk/StopPoint/{your-stop-id}/Arrivals` in a browser to check.\n- **Touch not responding** — verify the XPT2046 wiring matches the pin table above. Touch calibration values can be adjusted in `config.h`.\n- **Viewing serial output** — run `pio device monitor` to see live logs from the device.\n\n## Licence\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falopes%2Fesp32-tfl-bus-led","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falopes%2Fesp32-tfl-bus-led","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falopes%2Fesp32-tfl-bus-led/lists"}