{"id":25254916,"url":"https://github.com/happybono/businfosystem","last_synced_at":"2025-06-16T23:06:48.010Z","repository":{"id":54734213,"uuid":"290254982","full_name":"happybono/BusInfoSystem","owner":"happybono","description":"Bus Information System for Gyeonggi and Incheon Province, South Korea. NodeMCU (ESP8266) has been used as main microcontroller unit, and displays the bus information on the 0.96\" SSD1306 I2C OLED.","archived":false,"fork":false,"pushed_at":"2025-02-13T13:07:02.000Z","size":5961,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-02T18:50:22.870Z","etag":null,"topics":["arduino","arduino-ide","busarrival","busarrivaltimeprediction","cplusplus","cpp","esp8266","esp8266-projects","nodemcu-esp8266","open-api","openapi","openapis","public-api","public-apis","wifi","wifi-network"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/happybono.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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}},"created_at":"2020-08-25T15:38:45.000Z","updated_at":"2025-02-13T13:07:05.000Z","dependencies_parsed_at":"2025-01-18T18:31:46.603Z","dependency_job_id":"3aaef000-19f7-43e3-a789-c1d5b5a7e7a9","html_url":"https://github.com/happybono/BusInfoSystem","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/happybono/BusInfoSystem","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/happybono%2FBusInfoSystem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/happybono%2FBusInfoSystem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/happybono%2FBusInfoSystem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/happybono%2FBusInfoSystem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/happybono","download_url":"https://codeload.github.com/happybono/BusInfoSystem/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/happybono%2FBusInfoSystem/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260256257,"owners_count":22981807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","arduino-ide","busarrival","busarrivaltimeprediction","cplusplus","cpp","esp8266","esp8266-projects","nodemcu-esp8266","open-api","openapi","openapis","public-api","public-apis","wifi","wifi-network"],"created_at":"2025-02-12T05:39:56.515Z","updated_at":"2025-06-16T23:06:48.001Z","avatar_url":"https://github.com/happybono.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BusInfoSystem\nBus Information System for Gyeonggi province and Incheon metropolitan city, South Korea. NodeMCU (ESP8266) has been used as the main microcontroller unit, estimated arrival time calculated based on the real-time bus location data retrieved from the public data server once every 20 seconds. Displays refined information on the OLED Screen. \n\n\u003cdiv align=\"center\"\u003e\n\u003cimg alt=\"GitHub Last Commit\" src=\"https://img.shields.io/github/last-commit/happybono/BusInfoSystem\"\u003e \n\u003cimg alt=\"GitHub Repo Size\" src=\"https://img.shields.io/github/repo-size/happybono/BusInfoSystem\"\u003e\n\u003cimg alt=\"GitHub Repo Languages\" src=\"https://img.shields.io/github/languages/count/happybono/BusInfoSystem\"\u003e\n\u003cimg alt=\"GitHub Top Languages\" src=\"https://img.shields.io/github/languages/top/HappyBono/BusInfoSystem\"\u003e\n\u003c/div\u003e\n\n## What's New\n\u003cdetails\u003e\n\u003csummary\u003eClick to Expand\u003c/summary\u003e\n\n### v1.0\n#### August 25, 2020  \nInitial release.\n\n#### August 26, 2020  \nAdded Open API document which the Government of South Korea provides. \u003c/br\u003e\nModified variables to be consistent with bus route numbers.\n\n#### August 29, 2020\nBug Fixed : When there are \"no buses in service,\" the variable \"rcvbuf\" is not cleared.\n\n### v2.0\n#### May 12, 2021\nNow supports modified API and renewaled endpoint URL.\n\n#### July 1, 2023\nImprovements were made to serial logs to display more clearly.\n\n### v3.0\n#### January 12, 2025\nNow supports modified API and renewaled endpoint URL. \u003c/br\u003e\nBugs fixed.\n\n#### February 9, 2025\nEnhanced the system to retrieve bus route numbers from the API dynamically. \u003c/br\u003e\nImproved the Gyeonggi bus information system system to display an error message if the server fails to respond due to an error. \u003c/br\u003e\nBugs fixed.\n\n### v4.0\n#### February 9, 2025\nNow supports Incheon bus information system. \u003c/br\u003e\nImproved the Incheon bus information system to display an error message if the server fails to respond due to an error. \u003c/br\u003e\nIf the second bus with the same route number (has not departed/is not scheduled) or the first bus to arrive is less than or equal to 7 minutes, the estimated arrival time and the number of remaining stops for the first bus will display on the OLED Screen. \u003c/br\u003e\n\u003c/details\u003e\n\n## Project Setup\n1. Please download and install the necessary drivers and libraries.\n2. Replace `[Read API Key issued from the data.go.kr]` with your actual API key.\n3. Replace `[Your Wi-Fi SSID]` and `[Your Wi-Fi Password]` with your Wi-Fi credentials.\n4. Upload the code to your ESP8266 module.\n\n## Function Descriptions \u0026 Usage\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to Expand\u003c/summary\u003e\u003c/br\u003e\n  \n### `setup`\nInitializes the serial communication, OLED display, and Wi-Fi connection.\n\n#### Example\n```c++\nvoid setup() {\n  Serial.begin(9600);\n  setup_oled();\n  wifi_ready = connect_ap(ssid, password);\n  if (!wifi_ready){\n    nowifi_oled();\n  }\n}\n```\n\u003c/br\u003e\n\n### `loop`\nMain loop that checks for client data and updates the bus arrival times at set intervals.\n\n#### Example\n```c++\nvoid loop() {\n  while (client.available()) {\n    char c = client.read();\n    if (c != NULL) {\n      rcvbuf += c;\n      Serial.print(c);\n    }\n    yield();\n  }\n\n  if (millis() - previousMillis \u003e BISUPD_INTERVAL) {\n    resultBus1 = gBusParseArrivalTime(FormatBusString(ExtractBusNum()));\n    do_oled(0, 11, resultBus1);\n    do_oled(0, 22, resultBus2);\n    do_oled(0, 33, resultBus3);\n    requestLocker2 = true;\n  }\n  // Additional conditions...\n}\n```\n\u003c/br\u003e\n\n### `gBusRequestArrivalTime`\nSends a GET request to the API to get the arrival time of a specific bus at a particular station.\n\n#### Parameters\n`routeId (String)` : The route ID of the bus. \u003c/br\u003e\n`bstopId (String)` : The station (bus stop) ID.\n\n#### Example\n```c++\nvoid gBusRequestArrivalTime(String routeId, String stationId) {\n  String str = \"GET /6410000/busarrivalservice/v2/getBusArrivalItemv2?serviceKey=\" + gServiceKey + \"\u0026routeId=\";\n  str.concat(routeId);\n  str.concat(\"\u0026stationId=\");\n  str.concat(stationId);\n  str.concat(\"\u0026format=xml\");\n  str.concat(\" HTTP/1.1\\r\\nHost:apis.data.go.kr\\r\\nConnection: close\\r\\n\\r\\n\");\n\n  if (client.connect(gHost, httpPort)) {\n    Serial.println(\"gBusRequest(routeId = \" + routeId + \", stationId = \" + stationId + \" ) -- Connected\");\n    Serial.println(str);\n    client.print(str);\n    client.println();\n    // Additional code...\n  } else {\n    Serial.println(\"Connection failed\");\n  }\n}\n```\n\u003c/br\u003e\n\n### `iBusRequestArrivalTime`\nSends a GET request to the API to get the arrival time of a specific bus at a particular station.\n\n#### Parameters\n`routeId (String)` : The route ID of the bus. \u003c/br\u003e\n`bstopId (String)` : The station (bus stop) ID.\n\n#### Example\n```c++\nvoid iBusRequestArrivalTime(String routeId, String bstopId) {\n  String str = \"GET /6280000/busArrivalService/getBusArrivalList?serviceKey=\" + iServiceKey + \"\u0026pageNo=1\u0026numOfRows=10\u0026routeId=\";\n  str.concat(routeId);\n  str.concat(\"\u0026bstopId=\");\n  str.concat(bstopId);\n  str.concat(\" HTTP/1.1\\r\\nHost:apis.data.go.kr\\r\\nConnection: close\\r\\n\\r\\n\");\n\n  if (client.connect(iHost, httpPort)) {\n    Serial.println(\"connected\");\n    Serial.print(str);\n    client.print(str);\n    client.println();\n    // Additional code...\n  } else {\n    Serial.println(\"Connection Failed\");\n  }\n}\n```\n\u003c/br\u003e\n\n### `gBusParseArrivalTime`\nParses the arrival time of a general bus from the received buffer string.\n\n#### Parameters\n`busNum (String)` : The bus number.\n\n#### Example\n```c++\nString gBusParseArrivalTime(String busNum) {\n  previousMillis = millis();\n  int startIndex = rcvbuf.indexOf(\"\u003cpredictTime1\u003e\");\n  int endIndex;\n  String errCode;\n\n  if (startIndex == -1) {\n    startIndex = rcvbuf.indexOf(\"\u003creturnReasonCode\u003e\");\n    if (startIndex == -1) {\n      rcvbuf = \"\";\n      return busNum + \" : No buses in service\";\n    } else {\n      startIndex += strlen(\"\u003creturnReasonCode\u003e\");\n      endIndex = rcvbuf.indexOf(\"\u003c\", startIndex);\n      errCode = rcvbuf.substring(startIndex, endIndex);\n      rcvbuf = \"\";\n      return busNum + \" : Error Code ( \" + errCode + \" )\";\n    }\n  }\n\n  int strLength = strlen(\"\u003cpredictTimeX\u003e\");\n  endIndex = rcvbuf.indexOf(\"\u003c\", startIndex + strLength);\n  String predictTime1 = rcvbuf.substring(startIndex + strLength, endIndex);\n\n  startIndex = rcvbuf.indexOf(\"\u003cpredictTime2\u003e\") + strlen(\"\u003cpredictTime2\u003e\");\n  endIndex = rcvbuf.indexOf(\"\u003c\", startIndex);\n  String predictTime2 = rcvbuf.substring(startIndex, endIndex);\n\n  if (predictTime1 == \"\" \u0026\u0026 predictTime2 == \"\") {\n    return busNum + \" : No buses in service\";\n  }\n\n  if (predictTime2 == \"\" || predictTime1.toInt() \u003c= 7) {\n    startIndex = rcvbuf.indexOf(\"\u003clocationNo1\u003e\") + strlen(\"\u003clocationNo1\u003e\");\n    endIndex = rcvbuf.indexOf(\"\u003c\", startIndex);\n    String predictStop1 = rcvbuf.substring(startIndex, endIndex);\n    rcvbuf = \"\";\n    return busNum + \" : \" + (predictTime1 == \"1\" ? \"ARRIV.\" : predictTime1 + \" mins\") + (predictStop1 != \"\" ? \"  ( \" + predictStop1 + (predictStop1 == \"1\" ? \" stop )\" : \" stops )\") : \"\");\n  } else {\n    rcvbuf = \"\";\n    return busNum + \" : \" + (predictTime1 == \"1\" ? \"ARRIV.\" : predictTime1 + \" mins\") + (predictTime2 != \"\" ? \"  ,  \" + (predictTime2 == \"1\" ? \"ARRIV.\" : predictTime2 + \" mins\") : \"\");\n  }\n}\n```\n\u003c/br\u003e\n\n### `iBusParseArrivalTime`\nParses the arrival time of a general bus from the received buffer string.\n\n#### Parameters\n`busNum (String)` : The bus number.\n\n#### Example\n```c++\nString iBusParseArrivalTime(String busNum) {\n  previousMillis = millis();\n  int startIndex = rcvbuf.indexOf(\"\u003cARRIVALESTIMATETIME\u003e\");\n  int endIndex;\n  String errCode;\n\n  if (startIndex == -1) {\n    startIndex = rcvbuf.indexOf(\"\u003creturnReasonCode\u003e\");\n    if (startIndex == -1) {\n      rcvbuf = \"\";\n      return busNum + \" : No buses in service\";\n    } else {\n      startIndex += strlen(\"\u003creturnReasonCode\u003e\");\n      endIndex = rcvbuf.indexOf(\"\u003c\", startIndex);\n      errCode = rcvbuf.substring(startIndex, endIndex);\n      rcvbuf = \"\";\n      return busNum + \" : Error Code ( \" + errCode + \" )\";\n    }\n  }\n\n  startIndex += strlen(\"\u003cARRIVALESTIMATETIME\u003e\");\n  endIndex = rcvbuf.indexOf(\"\u003c\", startIndex);\n  String predictTime1 = rcvbuf.substring(startIndex, endIndex);\n\n  startIndex = rcvbuf.indexOf(\"\u003cREST_STOP_COUNT\u003e\") + strlen(\"\u003cREST_STOP_COUNT\u003e\");\n  endIndex = rcvbuf.indexOf(\"\u003c\", startIndex);\n  String predictStop1 = rcvbuf.substring(startIndex, endIndex);\n\n  String predictTime2;\n  int nextStartIndex = rcvbuf.indexOf(\"\u003cARRIVALESTIMATETIME\u003e\", startIndex);\n  if (nextStartIndex != -1) {\n    nextStartIndex += strlen(\"\u003cARRIVALESTIMATETIME\u003e\");\n    predictTime2 = rcvbuf.substring(nextStartIndex, rcvbuf.indexOf(\"\u003c\", nextStartIndex));\n  }\n  rcvbuf = \"\";\n\n  String strDisp;\n  strDisp.concat(busNum + \" : \");\n  int timeStr = predictTime1.toInt() / 60;\n  strDisp.concat(timeStr \u003e 1 ? String(timeStr) + \" mins\" : \"ARRIV.\");\n  if (predictTime2 != \"\") {\n    strDisp.concat(String(predictTime2.toInt() / 60) + \" mins\");\n  } else {\n    if (predictStop1 != \"\") {\n      strDisp.concat(\"  ( \" + predictStop1 + (predictStop1 == \"1\" ? \" stop )\" : \" stops )\"));\n    }\n  }\n\n  return strDisp;\n}\n```\n\u003c/br\u003e\n\n### `FormatBusString`\nFormats the bus number string to a consistent length for display purposes.\n\n#### Parameters\n`busStr (String)` : The bus number string to align center consistently.\n\n#### Example\n```c++\nString FormatBusString(String busStr) {\n  switch (busStr.length()) {\n    case 0:\n      return \"    \" + busStr + \"    \";\n    case 1:\n      return \"   \" + busStr + \"   \";\n    case 2:\n      return \"  \" + busStr + \"  \";\n    case 3:\n      return \" \" + busStr + \" \";\n    case 4:\n      if (busStr.indexOf(\"-\") == -1) {\n        return busStr;\n      } else {\n        return \" \" + busStr;\n      }\n    default:\n      return busStr;\n  }\n}\n```\n\u003c/br\u003e\n\n### `ExtractBusNum`\nExtracts the bus number from the received buffer string.\n\n#### Example\n```c++\nString ExtractBusNum() {\n  int startIndex = rcvbuf.indexOf(\"\u003crouteName\u003e\");\n  if (startIndex == -1) {\n    return \"\";\n  } else {\n    startIndex += strlen(\"\u003crouteName\u003e\");\n    int endIndex = rcvbuf.indexOf(\"\u003c\", startIndex);\n    return rcvbuf.substring(startIndex, endIndex);\n  }\n}\n```\n\u003c/details\u003e\n\n## Specifications\n### Scenarios\n- Estimated arrival time calculated based on the real-time bus location data retrieved from the server once every 20 seconds. Displays refined information on the OLED Screen.\n\n### Connections\n- 1 x Micro-USB\n\n### Wireless\n- IEEE 802.11 b/g/n Wi-Fi Technology\n\n## Apparatus (Equipment)\n### Platform\n- ESP8266 NodeMCU\n\n### 0.96\" SSD1306 I2C OLED Display \n* Soldering required\n* D3 : Data, D4 : Clock\n\n### KOKIRI A-PACK FIXIE 5 (KP-LS50) Portable Battery\n* USB Port : Power\n* Micro-USB : Charging Port\n* Dimension : 62.3 mm (W) × 112.0 mm (D) × 13.0 mm (H)\n* Weight : 120 g\n* Input : DC-5V / 2A\n* Output : DC-5V / 2.1A\n* Capacity : 5000 mAh\n\n## Schematics\n![BusInfoSystem-Schematics-Dark](BusInfoSystem-Schematics-Dark.png#gh-dark-mode-only)\n![BusInfoSystem-Schematics-Light](BusInfoSystem-Schematics-Light.png#gh-light-mode-only)\n\u003c/br\u003e\u003c/br\u003e\n![BIS_SCHEMDiag-Dark](BIS_SCHEMDiag-Dark.png#gh-dark-mode-only)\n![BIS_SCHEMDiag-Light](BIS_SCHEMDiag-Light.png#gh-light-mode-only)\n\u003c/br\u003e\u003c/br\u003e\n\n## Data Usage\n**1,126 bytes per API Call.** \u003cbr\u003e\n1,126 bytes (1.09 KB) x 3 = **3,378 bytes. (3 bus routes have been used in this project.)**\n \n86,400 ÷ 20 = **4,320 times API calls in a day.** \u003c/br\u003e\n4,320 * 3,378 = **14,592,960 bytes**. \u003c/br\u003e\nApproximately uses **13.92 MB per day.** (**418 MB per month.**)\n\n## Known Issues\n* The Incheon City Bus Arrival Information API only gives details on one arriving bus at a time, so it's impossible to show the expected arrival times for multiple buses on the OLED screen. \u003c/br\u003e\n* Since the Incheon City Bus Arrival Information API doesn't provide bus route numbers in its responses, you'll need to hard-code the bus route numbers in the code. \u003c/br\u003e\n* In cases where the Wi-Fi or server connection might not be stable, there may be instances when the OLED screen displays the message `No buses in service.` even if a server-related error code is not shown.\n\n## APIs Used\n### Gyeonggi-Do (Gyeonggi province) bus route inquiry API.\nhttps://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15080666\n- Provides the route ID, route type, and operating area of the route number.\n- Provides a list of stops via which the corresponding line stops, the name of the stop, whether the center lane is located, the turnaround point, and coordinate values.\n\n### Gyeonggi-Do (Gyeonggi province) bus arrival information inquiry API.\nhttps://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15080346\n- Provides location information, estimated arrival time, vacant seats, and low-floor bus information of the first and second scheduled buses for a specific route stopping at the corresponding stop.\n\n### Incheon metropolitan city bus route inquiry API.\nhttps://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15058487\n- Provides the route ID, route type, and operating area of the route number.\n- Provides a list of stops via which the corresponding line stops, the name of the stop, whether the center lane is located, the turnaround point, and coordinate values.\n\n### Incheon metropolitan city bus arrival information inquiry API.\nhttps://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15059084\n- Provides location information, estimated arrival time, vacant seats, and low-floor bus information of the first and second scheduled buses for a specific route stopping at the corresponding stop.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhappybono%2Fbusinfosystem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhappybono%2Fbusinfosystem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhappybono%2Fbusinfosystem/lists"}