{"id":50613862,"url":"https://github.com/hubertnshuti/bus-people-counting","last_synced_at":"2026-06-06T06:31:28.244Z","repository":{"id":356930362,"uuid":"1234549280","full_name":"hubertnshuti/bus-people-counting","owner":"hubertnshuti","description":"Real-time bus passenger counting system using ESP32 sensors, FastAPI, Streamlit, and ML-based occupancy prediction.","archived":false,"fork":false,"pushed_at":"2026-05-10T13:06:18.000Z","size":39,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-10T15:13:52.224Z","etag":null,"topics":["embedded-systems","esp32","fastapi","iot","machine-learning","passenger-counting","platformio","python","smart-transport","streamlit"],"latest_commit_sha":null,"homepage":"","language":"Python","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/hubertnshuti.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-05-10T10:32:22.000Z","updated_at":"2026-05-10T13:10:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hubertnshuti/bus-people-counting","commit_stats":null,"previous_names":["hubertnshuti/bus-people-counting"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/hubertnshuti/bus-people-counting","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubertnshuti%2Fbus-people-counting","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubertnshuti%2Fbus-people-counting/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubertnshuti%2Fbus-people-counting/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubertnshuti%2Fbus-people-counting/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hubertnshuti","download_url":"https://codeload.github.com/hubertnshuti/bus-people-counting/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubertnshuti%2Fbus-people-counting/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33972397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-06T02:00:07.033Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["embedded-systems","esp32","fastapi","iot","machine-learning","passenger-counting","platformio","python","smart-transport","streamlit"],"created_at":"2026-06-06T06:31:27.509Z","updated_at":"2026-06-06T06:31:28.231Z","avatar_url":"https://github.com/hubertnshuti.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bus People Counting\n\nA full-stack IoT system for real-time passenger counting on buses. An ESP32 with two ultrasonic sensors detects entries and exits through the doorway, streams events to a FastAPI backend, and a Streamlit dashboard shows live occupancy with a predictive model that estimates when the bus will reach capacity.\n\n---\n\n## How it works\n\n```\nPassengers → [Ultrasonic Sensors] → [ESP32] ──HTTP──► [FastAPI] ──► [SQLite]\n                                        ▲                               │\n                                        └────── device state ◄──────────┤\n                                                                        │\n                                        [Streamlit Dashboard] ◄─────────┘\n```\n\nTwo HC-SR04 sensors are mounted across the bus doorway. The firmware runs a state machine that tracks which sensor breaks first and which clears last — this gives reliable entry vs exit detection without any false counts from people hesitating or backing away.\n\nThe dashboard updates every second with no page flash (Streamlit fragments + pure HTML/CSS). A linear regression model, blended with a mechanical calculation, predicts how many minutes until the bus is full.\n\n---\n\n## Project structure\n\n```\nbus-people-counting/\n├── firmware/               ESP32 firmware (PlatformIO / Arduino)\n│   ├── src/main.cpp        Sensor reading, detection state machine, WiFi, HTTP\n│   ├── include/\n│   │   ├── config.h        ← gitignored, copy from config.h.example\n│   │   └── config.h.example\n│   └── platformio.ini\n│\n├── backend/                FastAPI server\n│   ├── app/\n│   │   ├── main.py         App entry point\n│   │   ├── database.py     SQLite connection + schema init\n│   │   ├── models.py       Pydantic request/response models\n│   │   └── routes/\n│   │       ├── events.py   POST /events, GET /events/recent\n│   │       └── device.py   GET/POST /device/state\n│   ├── data/               bus.db lives here (gitignored)\n│   ├── requirements.txt\n│   └── .env.example\n│\n├── dashboard/              Streamlit dashboard\n│   ├── app.py\n│   ├── .streamlit/config.toml\n│   └── requirements.txt\n│\n├── scripts/\n│   └── seed_history.py     Seeds 14 days of historical data for model training\n│\n└── docs/\n    └── wiring.md           Hardware wiring and sensor placement guide\n```\n\n---\n\n## Setup\n\n### 1. Firmware\n\nCopy the config template and fill in your WiFi credentials and server IP:\n\n```bash\ncp firmware/include/config.h.example firmware/include/config.h\n```\n\nEdit `firmware/include/config.h`:\n\n```c\n#define WIFI_SSID     \"your_network\"\n#define WIFI_PASSWORD \"your_password\"\n#define FALLBACK_SERVER_IP \"192.168.x.x\"   // IP of the machine running the backend\n```\n\nOpen the `firmware/` folder in VS Code with PlatformIO installed, then build and upload to the ESP32.\n\nSee `docs/wiring.md` for the full hardware wiring guide.\n\n### 2. Backend\n\n```bash\ncd backend\npip install -r requirements.txt\nuvicorn app.main:app --host 0.0.0.0 --port 8000 --reload\n```\n\nThe server creates `data/bus.db` on first run. Check `http://localhost:8000/docs` for the auto-generated API docs.\n\n### 3. Seed historical data (optional but recommended)\n\nThe prediction model needs enough training data to give useful predictions. Run the seed script once:\n\n```bash\npython scripts/seed_history.py\n```\n\nThis inserts 14 days of realistic boarding patterns (morning rush, lunch, afternoon rush, weekends) under `device_id='bus01-seed'`. Your real device data is never touched.\n\n### 4. Dashboard\n\n```bash\ncd dashboard\npip install -r requirements.txt\nstreamlit run app.py\n```\n\nOpen `http://localhost:8501`. Use the sidebar to set capacity, pause counting, or reset the counter — changes reach the device within one second.\n\n---\n\n## API endpoints\n\n| Method | Endpoint | Description |\n|---|---|---|\n| `GET` | `/health` | Health check |\n| `POST` | `/events` | Receive entry/exit event from ESP32 |\n| `GET` | `/events/recent` | Last N events |\n| `GET` | `/device/state` | Current capacity / paused / reset_token |\n| `POST` | `/device/state` | Update device control state |\n\n---\n\n## Firmware behaviour\n\n- **Direction detection**: sensor A (outer) → sensor B (inner) = entry. Reverse = exit.\n- **False positive filters**: partial pass (only one beam triggered), retreat (person backed away), timeout (passage took more than 5 seconds) are all discarded.\n- **Sensor fault detection**: if a sensor gives no valid reading for 6 seconds it is flagged; the LCD shows \"Please wait...\" so passengers aren't confused by raw debug messages.\n- **Event queue**: FreeRTOS queue (16 slots) buffers events during WiFi drops. No events are lost unless the queue overflows.\n- **Persistent count**: count survives power cycles via ESP32 NVS (Preferences). Reset via the dashboard sends a token; the device only zeros once per token so accidental double-resets don't happen.\n- **mDNS**: the device resolves `buscounter.local` first; falls back to a hardcoded IP if mDNS fails.\n\n---\n\n## Prediction model\n\nFeatures fed to the LinearRegression model:\n\n| Feature | Description |\n|---|---|\n| `current_count` | People currently on the bus |\n| `boarding_rate` | Entries per minute over the last 5 minutes |\n| `hour_of_day` | 0–23 |\n| `weekday` | 0=Monday … 6=Sunday |\n\nThe raw ML prediction is blended with a simple mechanical estimate `(capacity - count) / rate` at 40/60 weight. This keeps the prediction stable when the boarding rate is low or the model hasn't seen many similar situations.\n\n---\n\n## Hardware\n\n- ESP32 DOIT DevKit V1\n- 2× HC-SR04 ultrasonic sensors\n- 16×2 I2C LCD (address 0x27)\n- Green + Red LED with 220Ω resistors\n- Active 5V buzzer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhubertnshuti%2Fbus-people-counting","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhubertnshuti%2Fbus-people-counting","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhubertnshuti%2Fbus-people-counting/lists"}