Bus 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.
Click to Expand
Initial release.
Added Open API document which the Government of South Korea provides.
Modified variables to be consistent with bus route numbers.
Bug Fixed : When there are "no buses in service," the variable "rcvbuf" is not cleared.
Now supports modified API and renewaled endpoint URL.
Improvements were made to serial logs to display more clearly.
Now supports modified API and renewaled endpoint URL.
Bugs fixed.
Enhanced the system to retrieve bus route numbers from the API dynamically.
Improved the Gyeonggi bus information system system to display an error message if the server fails to respond due to an error.
Bugs fixed.
Now supports Incheon bus information system.
Improved the Incheon bus information system to display an error message if the server fails to respond due to an error.
If 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.
- Please download and install the necessary drivers and libraries.
- Replace
[Read API Key issued from the data.go.kr]
with your actual API key. - Replace
[Your Wi-Fi SSID]
and[Your Wi-Fi Password]
with your Wi-Fi credentials. - Upload the code to your ESP8266 module.
Click to Expand
Initializes the serial communication, OLED display, and Wi-Fi connection.
void setup() {
Serial.begin(9600);
setup_oled();
wifi_ready = connect_ap(ssid, password);
if (!wifi_ready){
nowifi_oled();
}
}
Main loop that checks for client data and updates the bus arrival times at set intervals.
void loop() {
while (client.available()) {
char c = client.read();
if (c != NULL) {
rcvbuf += c;
Serial.print(c);
}
yield();
}
if (millis() - previousMillis > BISUPD_INTERVAL) {
resultBus1 = gBusParseArrivalTime(FormatBusString(ExtractBusNum()));
do_oled(0, 11, resultBus1);
do_oled(0, 22, resultBus2);
do_oled(0, 33, resultBus3);
requestLocker2 = true;
}
// Additional conditions...
}
Sends a GET request to the API to get the arrival time of a specific bus at a particular station.
routeId (String)
: The route ID of the bus.
bstopId (String)
: The station (bus stop) ID.
void gBusRequestArrivalTime(String routeId, String stationId) {
String str = "GET /6410000/busarrivalservice/v2/getBusArrivalItemv2?serviceKey=" + gServiceKey + "&routeId=";
str.concat(routeId);
str.concat("&stationId=");
str.concat(stationId);
str.concat("&format=xml");
str.concat(" HTTP/1.1\r\nHost:apis.data.go.kr\r\nConnection: close\r\n\r\n");
if (client.connect(gHost, httpPort)) {
Serial.println("gBusRequest(routeId = " + routeId + ", stationId = " + stationId + " ) -- Connected");
Serial.println(str);
client.print(str);
client.println();
// Additional code...
} else {
Serial.println("Connection failed");
}
}
Sends a GET request to the API to get the arrival time of a specific bus at a particular station.
routeId (String)
: The route ID of the bus.
bstopId (String)
: The station (bus stop) ID.
void iBusRequestArrivalTime(String routeId, String bstopId) {
String str = "GET /6280000/busArrivalService/getBusArrivalList?serviceKey=" + iServiceKey + "&pageNo=1&numOfRows=10&routeId=";
str.concat(routeId);
str.concat("&bstopId=");
str.concat(bstopId);
str.concat(" HTTP/1.1\r\nHost:apis.data.go.kr\r\nConnection: close\r\n\r\n");
if (client.connect(iHost, httpPort)) {
Serial.println("connected");
Serial.print(str);
client.print(str);
client.println();
// Additional code...
} else {
Serial.println("Connection Failed");
}
}
Parses the arrival time of a general bus from the received buffer string.
busNum (String)
: The bus number.
String gBusParseArrivalTime(String busNum) {
previousMillis = millis();
int startIndex = rcvbuf.indexOf("<predictTime1>");
int endIndex;
String errCode;
if (startIndex == -1) {
startIndex = rcvbuf.indexOf("<returnReasonCode>");
if (startIndex == -1) {
rcvbuf = "";
return busNum + " : No buses in service";
} else {
startIndex += strlen("<returnReasonCode>");
endIndex = rcvbuf.indexOf("<", startIndex);
errCode = rcvbuf.substring(startIndex, endIndex);
rcvbuf = "";
return busNum + " : Error Code ( " + errCode + " )";
}
}
int strLength = strlen("<predictTimeX>");
endIndex = rcvbuf.indexOf("<", startIndex + strLength);
String predictTime1 = rcvbuf.substring(startIndex + strLength, endIndex);
startIndex = rcvbuf.indexOf("<predictTime2>") + strlen("<predictTime2>");
endIndex = rcvbuf.indexOf("<", startIndex);
String predictTime2 = rcvbuf.substring(startIndex, endIndex);
if (predictTime1 == "" && predictTime2 == "") {
return busNum + " : No buses in service";
}
if (predictTime2 == "" || predictTime1.toInt() <= 7) {
startIndex = rcvbuf.indexOf("<locationNo1>") + strlen("<locationNo1>");
endIndex = rcvbuf.indexOf("<", startIndex);
String predictStop1 = rcvbuf.substring(startIndex, endIndex);
rcvbuf = "";
return busNum + " : " + (predictTime1 == "1" ? "ARRIV." : predictTime1 + " mins") + (predictStop1 != "" ? " ( " + predictStop1 + (predictStop1 == "1" ? " stop )" : " stops )") : "");
} else {
rcvbuf = "";
return busNum + " : " + (predictTime1 == "1" ? "ARRIV." : predictTime1 + " mins") + (predictTime2 != "" ? " , " + (predictTime2 == "1" ? "ARRIV." : predictTime2 + " mins") : "");
}
}
Parses the arrival time of a general bus from the received buffer string.
busNum (String)
: The bus number.
String iBusParseArrivalTime(String busNum) {
previousMillis = millis();
int startIndex = rcvbuf.indexOf("<ARRIVALESTIMATETIME>");
int endIndex;
String errCode;
if (startIndex == -1) {
startIndex = rcvbuf.indexOf("<returnReasonCode>");
if (startIndex == -1) {
rcvbuf = "";
return busNum + " : No buses in service";
} else {
startIndex += strlen("<returnReasonCode>");
endIndex = rcvbuf.indexOf("<", startIndex);
errCode = rcvbuf.substring(startIndex, endIndex);
rcvbuf = "";
return busNum + " : Error Code ( " + errCode + " )";
}
}
startIndex += strlen("<ARRIVALESTIMATETIME>");
endIndex = rcvbuf.indexOf("<", startIndex);
String predictTime1 = rcvbuf.substring(startIndex, endIndex);
startIndex = rcvbuf.indexOf("<REST_STOP_COUNT>") + strlen("<REST_STOP_COUNT>");
endIndex = rcvbuf.indexOf("<", startIndex);
String predictStop1 = rcvbuf.substring(startIndex, endIndex);
String predictTime2;
int nextStartIndex = rcvbuf.indexOf("<ARRIVALESTIMATETIME>", startIndex);
if (nextStartIndex != -1) {
nextStartIndex += strlen("<ARRIVALESTIMATETIME>");
predictTime2 = rcvbuf.substring(nextStartIndex, rcvbuf.indexOf("<", nextStartIndex));
}
rcvbuf = "";
String strDisp;
strDisp.concat(busNum + " : ");
int timeStr = predictTime1.toInt() / 60;
strDisp.concat(timeStr > 1 ? String(timeStr) + " mins" : "ARRIV.");
if (predictTime2 != "") {
strDisp.concat(String(predictTime2.toInt() / 60) + " mins");
} else {
if (predictStop1 != "") {
strDisp.concat(" ( " + predictStop1 + (predictStop1 == "1" ? " stop )" : " stops )"));
}
}
return strDisp;
}
Formats the bus number string to a consistent length for display purposes.
busStr (String)
: The bus number string to align center consistently.
String FormatBusString(String busStr) {
switch (busStr.length()) {
case 0:
return " " + busStr + " ";
case 1:
return " " + busStr + " ";
case 2:
return " " + busStr + " ";
case 3:
return " " + busStr + " ";
case 4:
if (busStr.indexOf("-") == -1) {
return busStr;
} else {
return " " + busStr;
}
default:
return busStr;
}
}
Extracts the bus number from the received buffer string.
String ExtractBusNum() {
int startIndex = rcvbuf.indexOf("<routeName>");
if (startIndex == -1) {
return "";
} else {
startIndex += strlen("<routeName>");
int endIndex = rcvbuf.indexOf("<", startIndex);
return rcvbuf.substring(startIndex, endIndex);
}
}
- 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.
- 1 x Micro-USB
- IEEE 802.11 b/g/n Wi-Fi Technology
- ESP8266 NodeMCU
- Soldering required
- D3 : Data, D4 : Clock
- USB Port : Power
- Micro-USB : Charging Port
- Dimension : 62.3 mm (W) × 112.0 mm (D) × 13.0 mm (H)
- Weight : 120 g
- Input : DC-5V / 2A
- Output : DC-5V / 2.1A
- Capacity : 5000 mAh
1,126 bytes per API Call.
1,126 bytes (1.09 KB) x 3 = 3,378 bytes. (3 bus routes have been used in this project.)
86,400 ÷ 20 = 4,320 times API calls in a day.
4,320 * 3,378 = 14,592,960 bytes.
Approximately uses 13.92 MB per day. (418 MB per month.)
- 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.
- 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.
- 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.
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15080666
- Provides the route ID, route type, and operating area of the route number.
- 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.
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15080346
- 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.
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15058487
- Provides the route ID, route type, and operating area of the route number.
- 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.
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15059084
- 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.