Project showcase
SL Real Time Information 4

SL Real Time Information 4 © CC BY-SA

Arduino sketch written for NodeMCU to fetch information from Stockholm Lokaltrafiks API about departures from any given stop.

  • 190 views
  • 0 comments
  • 1 respect

Components and supplies

Apps and online services

About this project

This project was about interfacing a small RAM microcontroller with the massive REST interface of the SL API, to parse json documents orders of magnitude bigger than the RAM and to make that data easily accessible to the user.

I tried many approaches but settled upon the excellent ArduinoJson library.

The code is easy to remix and use in your own project.

Code

SL_Real_Time_Information_4.inoArduino
Just add API keys and your wifi credentials
/*
  This sketch makes use of the SL Realtidsinformation 4 API
  to fetch and present the json data in the serial monitor.
  It's written to be easily remixable to fit your project.

  Read about the APIs here:
  https://www.trafiklab.se/api/sl-realtidsinformation-4
  https://www.trafiklab.se/api/sl-platsuppslag
*/


#include <WiFiClient.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>

// Enter your WiFi credentials here:
const char* wifiName   = "your-wifi";
const char* wifiPass   = "your-pass";

// Enter your API key for SL Platsuppslag here (if you don't need SL Platsuppslag just set fetchStopInfo to false):
const char* PUAPIKey       = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

// Enter your API key for SL Realtidsinformation 4 here:
const char* RTD4APIKey     = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// Enter site ID (e.g. 9001 for T-centralen, 9192 for Slussen):
const char* RTD4siteID     = "9001";
// Enter time window (60 minutes is max):
const char* RTD4timeWindow = "60";

const bool fetchStopInfo = true;// Set to false if not using the SL Platsuppslag API.

const bool lookForMetros = true;
const bool lookForBuses  = true;
const bool lookForTrains = true;
const bool lookForTrams  = true;
const bool lookForShips  = true;

const bool lookForStopPointDeviations  = true;

WiFiClient client;

DynamicJsonDocument doc(16 * 1024);

void setup() {

  Serial.begin(115200);
  delay(10);
  Serial.println();

  Serial.print("Connecting to ");
  Serial.println(wifiName);

  WiFi.begin(wifiName, wifiPass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }


  Serial.println();
  Serial.println("WiFi connected.");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());   //You can get IP address assigned to ESP


  if (fetchStopInfo) {
    stopInfoFetcher(PUAPIKey, RTD4siteID);
  }


}
void loop() {

  client.connect("api.sl.se", 80);

  client.print("GET /api2/realtimedeparturesV4.json?key=");
  client.print(RTD4APIKey);
  client.print("&siteid=");
  client.print(RTD4siteID);
  client.print("&timewindow=");
  client.print(RTD4timeWindow);
  client.println(" HTTP/1.0");
  client.println("Host: api.sl.se");
  client.println("Connection: close");
  client.println();

  if (lookForMetros) {
    findTransport("Metros");
  }

  if (lookForBuses) {
    findTransport("Buses");
  }

  if (lookForTrains) {
    findTransport("Trains");
  }

  if (lookForTrams) {
    findTransport("Trams");
  }

  if (lookForShips) {
    findTransport("Ships");
  }

  if (lookForStopPointDeviations) {
    findStopPointDeviations();
  }


  client.stop();

  delay(300000);  //GET Data at every 5 minutes
}

void stopInfoFetcher(const char* APIkey, const char* siteID) {
  client.connect("api.sl.se", 80);

  client.print("GET /api2/typeahead.json?key=");
  client.print(APIkey);
  client.print("&searchstring=");
  client.print(siteID);
  client.print("&stationsonly=True&maxresults=1");
  client.println(" HTTP/1.0");
  client.println("Host: api.sl.se");
  client.println("Connection: close");
  client.println();

  client.find("\"ResponseData\":[");
  Serial.println();
  Serial.println(F("Stop Point Info: "));
  do {
    // Parse the JSON object
    deserializeJson(doc, client);
    if (doc.isNull()) {
      Serial.println("No stop info found.");
      break;
    }
    Serial.print(F("Name: "));
    Serial.println(doc["Name"].as<char*>());
    Serial.print(F("SiteId: "));
    Serial.println(doc["SiteId"].as<char*>());
    Serial.print(F("Type: "));
    Serial.println(doc["Type"].as<char*>());
    Serial.print(F("X: "));
    Serial.println(doc["X"].as<char*>());
    Serial.print(F("Y: "));
    Serial.println(doc["Y"].as<char*>());
    Serial.print(F("Products: "));
    Serial.println(doc["Products"].as<char*>());
  }
  while (client.findUntil(",", "]"));

  client.stop();

}




void findTransport(char* type) {
  Serial.println();
  Serial.print(F("#### "));
  Serial.print(type);
  Serial.println(F(" ####"));
  char* beginning = "\"";
  char* ending = "\":[";
  char searchTerm[20];
  sprintf(searchTerm, "%s%s%s", beginning, type, ending);

  client.find(searchTerm);

  do {
    // Parse the JSON object
    deserializeJson(doc, client);
    if (doc.isNull()) {
      Serial.print("No ");
      Serial.print(type);
      Serial.println(" found.");
      break;
    }
    Serial.println();
    Serial.print(F("GroupOfLine: "));
    Serial.println(doc["GroupOfLine"].as<char*>());
    Serial.print(F("DisplayTime: "));
    Serial.println(doc["DisplayTime"].as<char*>());
    Serial.print(F("TransportMode: "));
    Serial.println(doc["TransportMode"].as<char*>());
    Serial.print(F("LineNumber: "));
    Serial.println(doc["LineNumber"].as<char*>());
    Serial.print(F("Destination: "));
    Serial.println(doc["Destination"].as<char*>());
    Serial.print(F("JourneyDirection: "));
    Serial.println(doc["JourneyDirection"].as<int>());
    Serial.print(F("StopAreaName: "));
    Serial.println(doc["StopAreaName"].as<char*>());
    Serial.print(F("StopAreaNumber: "));
    Serial.println(doc["StopAreaNumber"].as<int>());
    Serial.print(F("StopPointNumber: "));
    Serial.println(doc["StopPointNumber"].as<int>());
    Serial.print(F("StopPointDesignation: "));
    Serial.println(doc["StopPointDesignation"].as<char*>());
    Serial.print(F("TimeTabledDateTime: "));
    Serial.println(doc["TimeTabledDateTime"].as<char*>());
    Serial.print(F("ExpectedDateTime: "));
    Serial.println(doc["ExpectedDateTime"].as<char*>());
    Serial.print(F("JourneyNumber: "));
    Serial.println(doc["JourneyNumber"].as<int>());
    if (doc["Deviations"].isNull() == false) {
      Serial.println(F("# Deviations #"));
    }
    for (int i = 0; i < doc["Deviations"].size(); i++) {
      Serial.print(F("Text: "));
      Serial.println(doc["Deviations"][i]["Text"].as<char*>());
      Serial.print(F("Consequence: "));
      Serial.println(doc["Deviations"][i]["Consequence"].as<char*>());
      Serial.print(F("ImportanceLevel: "));
      Serial.println(doc["Deviations"][i]["ImportanceLevel"].as<int>());
    }



  } while (client.findUntil(",", "]"));
}

void findStopPointDeviations() {
  client.find("\"StopPointDeviations\":[");
  Serial.println();
  Serial.println(F("#### Stop Point Deviations ####"));
  do {
    // Parse the JSON object
    deserializeJson(doc, client);
    if (doc.isNull()) {
      Serial.println("No stop point deviations found.");
      break;
    }
    Serial.println(F("# StopInfo #"));
    Serial.print(F("StopAreaNumber: "));
    Serial.println(doc["StopInfo"]["StopAreaNumber"].as<int>());
    Serial.print(F("StopAreaName: "));
    Serial.println(doc["StopInfo"]["StopAreaName"].as<char*>());
    Serial.print(F("TransportMode: "));
    Serial.println(doc["StopInfo"]["TransportMode"].as<char*>());
    Serial.print(F("GroupOfLine: "));
    Serial.println(doc["StopInfo"]["GroupOfLine"].as<char*>());
    Serial.println(F("# Deviation #"));
    Serial.print(F("Text: "));
    Serial.println(doc["Deviation"]["Text"].as<char*>());
    Serial.print(F("Consequence: "));
    Serial.println(doc["Deviation"]["Consequence"].as<char*>());
    Serial.print(F("ImportanceLevel: "));
    Serial.println(doc["Deviation"]["ImportanceLevel"].as<int>());

  } while (client.findUntil(",", "]"));
}

Schematics

Breadboard
Schematic of hookup onto the breadboard. The NodeMCU will accept any voltage up to 20 Volts.
Sl api nodemcu schem bb mfaka0eabt

Comments

Similar projects you might like

LCD with DS3231 Real Time Clock Module

Project showcase by Tan See Youu

  • 47,761 views
  • 0 comments
  • 40 respects

Arduino OLED Temperature Display with Real Time Clock

Project tutorial by Keval Doshi

  • 12,692 views
  • 8 comments
  • 35 respects

Real Time Clock (RTC) PCF8563

by Arduino_Scuola

  • 9,001 views
  • 1 comment
  • 7 respects

Real time LPG monitoring system

Project showcase by TEAM DIY

  • 3,486 views
  • 2 comments
  • 4 respects

LED Ring Real Time Clock

Project showcase by 3 developers

  • 1,438 views
  • 0 comments
  • 1 respect

Remote Control bot

by vedrocks15

  • 1,279 views
  • 0 comments
  • 1 respect
Add projectSign up / Login