Singapore Bus Arrival - Can someone advice on the code?

I keep getting dropped API, where only the first API call is successful, follow by 0 or a few calls. Rest are unable to get the API. Any advice? Thanks in Advance, Damien Lee



#include <WiFiS3.h>

#include <ArduinoHttpClient.h>

#include <Arduino_JSON.h>

#include <Adafruit_GFX.h>

#include <Adafruit_ILI9341.h>




// WiFi credentials

const char* ssid = "TMOCETALxxxxxx";

const char* password = "TMOCxxxxxxx";




// LTA DataMall API details

const char* host = "datamall2.mytransport.sg";

const int httpsPort = 443;

const char* apiPath = "/ltaodataservice/v3/BusArrival?BusStopCode=10411&ServiceNo=63";

const char* accountKey = "xxxxxxx";




// TFT LCD pins (Adafruit 2.8" shield default)

#define TFT_CS   10

#define TFT_DC    9

#define TFT_RST   8




Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);




// WiFi and HTTP objects

WiFiSSLClient wifiClient;

HttpClient client = HttpClient(wifiClient, host, httpsPort);




int countUp = 0; // variable integer




unsigned long lastUpdate = 0;

const unsigned long updateInterval = 20000; // 20 seconds




void setup() { 

  Serial.begin(115200);

  tft.begin();

  tft.setRotation(1);

  tft.fillScreen(ILI9341_BLACK);

  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

  tft.setTextSize(2);

  tft.setCursor(10, 10);

  tft.println("Connecting WiFi...");

  

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    tft.print(".");

  }

} 




void loop() {

 WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    tft.print(".");

  }




  if (millis() - lastUpdate > updateInterval || lastUpdate == 0) {

    lastUpdate = millis();

    displayBusArrival();

  }

}

void displayBusArrival() {

  tft.fillScreen(ILI9341_BLACK);

  tft.setCursor(10, 10);

  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

  tft.setTextSize(3);

  tft.println("SINGAPORE BUS");

  tft.println(" ARRIVAL");

  tft.setTextColor(ILI9341_RED, ILI9341_BLACK);

  tft.setTextSize(2);

  tft.println(" DEVELOPED BY DAMIEN LEE");

  tft.println("");

  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);

  tft.setTextSize(2);

  tft.println("Service : 63");

  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);

  tft.setTextSize(2);

  tft.println("Bus Stop: 10411");

  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

  tft.setTextSize(2);

  client.beginRequest();

  client.get(apiPath);

  client.sendHeader("AccountKey", accountKey);

  client.sendHeader("Accept", "application/json");

  client.endRequest();

  countUp++; // add 1 to the count

  tft.println("");

  tft.println(countUp); // prints out the count

  int statusCode = client.responseStatusCode();

  String response = client.responseBody();




  if (statusCode != 200) {

    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);

    tft.println("API Error!");

    tft.print("Status: ");

    tft.println("*");

    tft.println(statusCode);

    return;

  }




  JSONVar data = JSON.parse(response);

  if (JSON.typeof(data) == "undefined") {

    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);

    tft.println(".");

    JSONVar data = null;    

    return;

  }




  JSONVar services = data["Services"];

  if (services.length() > 0) {

    JSONVar svc = services[0];

    JSONVar nextBus = svc["NextBus"];

    JSONVar nextBus2 = svc["NextBus2"];

    JSONVar nextBus3 = svc["NextBus3"];

    tft.setTextColor(ILI9341_CYAN, ILI9341_BLACK);

    tft.println("Next 3 Arrivals:");

    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

    tft.print("1: ");

    tft.println(formatTime(nextBus["EstimatedArrival"]));

    tft.print("2: ");

    tft.println(formatTime(nextBus2["EstimatedArrival"]));

    tft.print("3: ");

    tft.println(formatTime(nextBus3["EstimatedArrival"]));

  } else {

    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);

    tft.println("No service info.");

  }

    wifiClient.stop(); // Close connection after successful request

}




// Helper to format ISO time to HH:MM or "--"

String formatTime(JSONVar isoTime) {

  String t = (const char*)isoTime;

  if (t.length() < 16) return "--";

  // Format: "YYYY-MM-DDTHH:MM:SS+08:00"

  return t.substring(11, 16);

you should not restart the wifi connection in the loop. Check if it is active but don't force restart it all the time !

try something like

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) { delay(500); }
  }

  if (millis() - lastUpdate > updateInterval || lastUpdate == 0) {
    lastUpdate = millis();
    displayBusArrival();
  }
}

thank you. let me try!

@J-M-L can you PM me? I pass you the api key.

It is better now, but beyond the 7th read, the data is empty . It seems that unplugging the usb and resetting the R4 will obtain stable results for 5 reads, then subsequent reads are empty. until the 14th, data is back. 15th empty and so on.

I don’t have an R4
Can you post full code and details about your wiring and power ?



#include <WiFiS3.h>

#include <ArduinoHttpClient.h>

#include <Arduino_JSON.h>

#include <Adafruit_GFX.h>

#include <Adafruit_ILI9341.h>

// WiFi credentials

const char* ssid = "xxx_5G";

const char* password = "xxxx";

// LTA DataMall API details

const char* host = "datamall2.mytransport.sg";

const int httpsPort = 443;

const char* apiPath = "/ltaodataservice/v3/BusArrival?BusStopCode=10411&ServiceNo=63";

const char* accountKey = "xxxx==";

// TFT LCD pins (Adafruit 2.8" shield default)

#define TFT_CS   10

#define TFT_DC    9

#define TFT_RST   8

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

// WiFi and HTTP objects

WiFiSSLClient wifiClient;

HttpClient client = HttpClient(wifiClient, host, httpsPort);

int countUp = 0; // variable integer

unsigned long lastUpdate = 0;

const unsigned long updateInterval = 20000; // 20 seconds

void setup() {

Serial.begin(115200);

tft.begin();

tft.setRotation(1);

tft.fillScreen(ILI9341_BLACK);

tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

tft.setTextSize(2);

tft.setCursor(10, 10);

tft.println("Connecting WiFi...");



WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {

tft.print(".");

}

}

void loop() {

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {

tft.print(".");

}

if (millis() - lastUpdate > updateInterval || lastUpdate == 0) {

lastUpdate = millis();

displayBusArrival();

}

}

void displayBusArrival() {

tft.fillScreen(ILI9341_BLACK);

tft.setCursor(10, 10);

tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

tft.setTextSize(3);

tft.println("SINGAPORE BUS");

tft.println(" ARRIVAL");

tft.setTextColor(ILI9341_RED, ILI9341_BLACK);

tft.setTextSize(2);

tft.println(" DEVELOPED BY DAMIEN LEE");

tft.println("");

tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);

tft.setTextSize(2);

tft.println("Service : 63");

tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);

tft.setTextSize(2);

tft.println("Bus Stop: 10411");

tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

tft.setTextSize(2);

client.beginRequest();

client.get(apiPath);

client.sendHeader("AccountKey", accountKey);

client.sendHeader("Accept", "application/json");

client.endRequest();

countUp++; // add 1 to the count

tft.println("");

tft.println(countUp); // prints out the count

int statusCode = client.responseStatusCode();

String response = client.responseBody();

if (statusCode != 200) {

tft.setTextColor(ILI9341_RED, ILI9341_BLACK);

tft.println("API Error!");

tft.print("Status: ");

tft.println("*");

tft.println(statusCode);

return;

}

JSONVar data = JSON.parse(response);

if (JSON.typeof(data) == "undefined") {

tft.setTextColor(ILI9341_RED, ILI9341_BLACK);

tft.println(".");

JSONVar data = null;

return;

}

JSONVar services = data["Services"];

if (services.length() > 0) {

JSONVar svc = services[0];

JSONVar nextBus = svc["NextBus"];

JSONVar nextBus2 = svc["NextBus2"];

JSONVar nextBus3 = svc["NextBus3"];

tft.setTextColor(ILI9341_CYAN, ILI9341_BLACK);

tft.println("Next 3 Arrivals:");

tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

tft.print("1: ");

tft.println(formatTime(nextBus["EstimatedArrival"]));

tft.print("2: ");

tft.println(formatTime(nextBus2["EstimatedArrival"]));

tft.print("3: ");

tft.println(formatTime(nextBus3["EstimatedArrival"]));

} else {

tft.setTextColor(ILI9341_RED, ILI9341_BLACK);

tft.println("No service info.");

}

//   wifiClient.stop(); // Close connection after successful request

}

// Helper to format ISO time to HH:MM or "--"

String formatTime(JSONVar isoTime) {

String t = (const char*)isoTime;

if (t.length() < 16) return "--";

// Format: "YYYY-MM-DDTHH:MM:SS+08:00"

return t.substring(11, 16);

}


What did i say about that ?

You might also need to properly end the client session with wifiClient.stop();

appreciate if you can paste the whole code here? my limitied knowledge is an impairment. lolx

I have tried your suggestions but still there are significant drops with the data.

try this - edited here, fully untested

#include <WiFiS3.h>
#include <ArduinoHttpClient.h>
#include <Arduino_JSON.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>

// ************************************************************************
// ******** PUT YOUR REAL VALUES HERE (DON'T SHARE WITH THE FORUM) ********
// ************************************************************************
const char* ssid = "xxx_5G";
const char* password = "xxxx";
const char* accountKey = "xxx==";

// ************************************************************************
// ************************************************************************

const char* host = "datamall2.mytransport.sg";
const int httpsPort = 443;

#define SERVICE_NO "63"
#define BUS_STOP_CODE "10411"

const char* apiPath = "/ltaodataservice/v3/BusArrival?BusStopCode=" BUS_STOP_CODE "&ServiceNo=" SERVICE_NO;

#define TFT_CS   10
#define TFT_DC    9
#define TFT_RST   8

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

WiFiSSLClient wifiClient;

int countUp = 0;
const unsigned long updateInterval = 20000;
unsigned long lastUpdate = -updateInterval;
const unsigned long wifiTimeout = 15000;

void displayBusArrival() {
  if (WiFi.status() != WL_CONNECTED) {
    tft.fillScreen(ILI9341_BLACK);
    tft.setCursor(10, 10);
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    tft.setTextSize(2);
    tft.println("WiFi disconnected!");
    tft.println("Reconnecting...");

    WiFi.disconnect();
    WiFi.begin(ssid, password);
    unsigned long start = millis();
    while (WiFi.status() != WL_CONNECTED) {
      if (millis() - start > wifiTimeout) {
        tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
        tft.println("WiFi reconnect failed!");
        return;
      }
      delay(500);
    }
    tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
    tft.println("WiFi reconnected");
    delay(1000);
  }


  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(10, 10);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setTextSize(3);
  tft.println("SINGAPORE BUS");
  tft.println(" ARRIVAL");
  tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
  tft.setTextSize(2);
  tft.println("BY J-M-L FOR D. LEE");
  tft.println();
  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  tft.setTextSize(2);
  tft.print("Service : ");
  tft.println(SERVICE_NO);
  tft.print("Bus Stop: ");
  tft.println(BUS_STOP_CODE);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setTextSize(2);

  HttpClient client = HttpClient(wifiClient, host, httpsPort);

  client.beginRequest();
  client.get(apiPath);
  client.sendHeader("AccountKey", accountKey);
  client.sendHeader("Accept", "application/json");
  client.endRequest();

  countUp++;
  tft.println();
  tft.println(countUp);

  int statusCode = client.responseStatusCode();
  String response = client.responseBody();
  client.stopConnection();

  if (statusCode != 200) {
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.println("API Error!");
    tft.print("Status: ");
    tft.println(statusCode);
    return;
  }

  JSONVar data = JSON.parse(response);
  if (JSON.typeof(data) == "undefined") {
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.println("JSON parse error");
    return;
  }

  JSONVar services = data["Services"];
  if (services.length() > 0) {
    JSONVar svc = services[0];

    tft.setTextColor(ILI9341_CYAN, ILI9341_BLACK);
    tft.println("Next 3 Arrivals:");
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

    printBusArrival(svc, "NextBus", 1);
    printBusArrival(svc, "NextBus2", 2);
    printBusArrival(svc, "NextBus3", 3);
  } else {
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.println("No service info.");
  }
}

void printBusArrival(JSONVar svc, const char* key, int index) {
  if (!svc.hasOwnProperty(key)) return;
  JSONVar bus = svc[key];
  if (!bus.hasOwnProperty("EstimatedArrival")) return;
  tft.print(index);
  tft.print(": ");
  tft.println(formatTime(bus["EstimatedArrival"]));
}

String formatTime(JSONVar isoTime) {
  String t = (const char*)isoTime;
  if (t.length() < 16) return "--";
  return t.substring(11, 16);
}

// --------------- MAIN CODE --------------

void setup() {
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setTextSize(2);
  tft.setCursor(10, 10);
  tft.println("Connecting WiFi...");

  WiFi.begin(ssid, password);
  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED) {
    if (millis() - start > wifiTimeout) {
      tft.println();
      tft.println("WiFi Failed");
      return;
    }
    tft.print(".");
    delay(500);
  }
  tft.println();
  tft.println("WiFi Connected");
}

void loop() {
  if (millis() - lastUpdate >= updateInterval) {
    lastUpdate = millis();
    displayBusArrival();
  }
}

you'll have to set your correct info into

// ************************************************************************
// ******** PUT YOUR REAL VALUES HERE (DON'T SHARE WITH THE FORUM) ********
// ************************************************************************
const char* ssid = "xxx_5G";
const char* password = "xxxx";
const char* accountKey = "xxx==";

// ************************************************************************
// ************************************************************************

thanks bro. Do you want a full set of R4 Uno and 2.8TFT above? I can send you one set free of charge. You can keep it after testing.

I got this error:

C:\Users\damien.lee.AAS\OneDrive - Automobile Association Of Singapore\Documents\Arduino\SG_BUS_Final_V3_JML\SG_BUS_Final_V3_JML.ino: In function 'void displayBusArrival()':
C:\Users\damien.lee.AAS\OneDrive - Automobile Association Of Singapore\Documents\Arduino\SG_BUS_Final_V3_JML\SG_BUS_Final_V3_JML.ino:97:10: error: 'class HttpClient' has no member named 'stopConnection'
client.stopConnection();
^~~~~~~~~~~~~~
exit status 1

Compilation error: 'class HttpClient' has no member named 'stopConnection'

Can you try stop() instead of stopConnection(). - it’s likely what’s it’s called in ArduinoHttpClient actually.

No need for shipping something around - thx for the offer though.

Thank you! Its fully working now.

Glad to have your guidance bro.

cool - have fun.