Transport for London Unified API schedule
This flow uses the Unified TFL API to pull in train schedule data for a local London train station. It then extracts and filters out the next train times and destinations. The schedule data is then formatted and sent to an OLED screen powered by an Arduino compatible board via MQTT messaging.
More info on TFL API: https://api-portal.tfl.gov.uk/docs
##Complete write-up: ###http://www.internetoflego.com/train-schedule-display-2/
##Usage
An inject node will perform a GET request to the TFL service, where the msg.stationid specifies the station schedule
msg.url = "https://api.tfl.gov.uk/StopPoint/"+msg.stationid+"/arrivals";
The data will then be sent out using MQTT, to be received by the Arduino powered OLED display.
The flow also includes additional APIs to retrieve the formatted schedule on demand.
####http://yourserver.com:1880/trainschedule?station=910GLONFLDS
Forces an API lookup with the specified train station ID
Test APIs to see data
These URLs will look to the local flow context variable to display the most recent schedule
####http://yourserver.com:1880/trainjson
{"station":"London Fields Rail Station","schedule":[{"expected":0,"destination":"Enfield Town Rail Station"},{"expected":3,"destination":"Cheshunt Rail Station"},{"expected":18,"destination":"Enfield Town Rail Station"},{"expected":26,"destination":"Cheshunt Rail Station"},{"expected":33,"destination":"Enfield Town Rail Station"},{"expected":48,"destination":"Enfield Town Rail Station"},{"expected":63,"destination":"Cheshunt Rail Station"}]}
####http://yourserver.com:1880/traindisplay
London Fields Rail Station
0min Cheshunt Rail Station
11min Enfield Town Rail Station 1
9min Cheshunt Rail Station
26min Enfield Town Rail Station
41min Enfield Town Rail Station
56min Cheshunt Rail Station
71min Enfield Town Rail Station
#Note This flow requires Node-RED 0.13.0 to make use of the flow context variable.
Written by: Cory Guynn, 2016 www.InternetOfLEGO.com
[{"id":"e33ec540.1cc138","type":"ui_tab","z":"","name":"IoL","icon":"dashboard","order":"1"},{"id":"b1d8d4eb.4e2728","type":"mqtt-broker","z":"e60e9052.19f17","broker":"","port":"1883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":"false","willPayload":"","birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":""},{"id":"4419e8c7.bbe618","type":"http request","z":"e60e9052.19f17","name":"API Call","method":"GET","ret":"txt","url":"","x":680,"y":120,"wires":[["9cb083cd.634f8","2ddf34e0.d220cc"]]},{"id":"4bf1e239.b40e1c","type":"inject","z":"e60e9052.19f17","name":"","topic":"","payload":"910GLONFLDS","payloadType":"string","repeat":"1","crontab":"","once":true,"x":140,"y":140,"wires":[["110734c1.eef8cb"]]},{"id":"9a4a5cb0.65b5a","type":"function","z":"e60e9052.19f17","name":"Request URL to TFL","func":"msg.stationid = msg.payload;\nmsg.url = \"https://api.tfl.gov.uk/StopPoint/\"+msg.stationid+\"/arrivals\";\nreturn msg;","outputs":1,"noerr":0,"x":500,"y":120,"wires":[["4419e8c7.bbe618"]]},{"id":"9cb083cd.634f8","type":"debug","z":"e60e9052.19f17","name":"TFL API response","active":true,"console":"false","complete":"payload","x":870,"y":120,"wires":[]},{"id":"9e12935e.61ed7","type":"debug","z":"e60e9052.19f17","name":"TFL Next Trains","active":true,"console":"false","complete":"payload","x":660,"y":220,"wires":[]},{"id":"2ddf34e0.d220cc","type":"json","z":"e60e9052.19f17","name":"","x":810,"y":160,"wires":[["2e361136.d1c9ee"]]},{"id":"b09a07d2.4f65f8","type":"http in","z":"e60e9052.19f17","name":"/trainschedule?station=910GLONFLDS","url":"/trainschedule","method":"get","swaggerDoc":"","x":190,"y":60,"wires":[["aca72f6.f5358d"]]},{"id":"aca72f6.f5358d","type":"function","z":"e60e9052.19f17","name":"request","func":"//msg.payload = \"910GLONFLDS\";\nmsg.payload = msg.req.station || \"910GLONFLDS\" ;\nreturn msg;","outputs":1,"noerr":0,"x":460,"y":60,"wires":[["9a4a5cb0.65b5a","51f23f28.ae0dc"]]},{"id":"f628b4f.f09d748","type":"http response","z":"e60e9052.19f17","name":"","x":630,"y":260,"wires":[]},{"id":"6b14d440.94eb2c","type":"comment","z":"e60e9052.19f17","name":"TFL Schedule","info":"","x":90,"y":20,"wires":[]},{"id":"4e1f5b18.b1e0a4","type":"comment","z":"e60e9052.19f17","name":"Sort Outbound Trains","info":"","x":120,"y":220,"wires":[]},{"id":"2e361136.d1c9ee","type":"function","z":"e60e9052.19f17","name":"Outbound Schedule new schema","func":"var tfl = msg.payload;\nvar trains = {};\nvar station;\nvar expected;\nvar nextTrains = [];\n\n\n// check for valid data first\nif (msg.statusCode == 200) {\n //if(tfl[0] !== undefined){\n if(tfl[0]){\n station = tfl[0].stationName;\n\n // sort schedule\n tfl.sort(function(a,b){\n \t return (a.timeToStation - b.timeToStation);\n \t});\n \n // iterate through all schedule records and save required data\n for (var i = 0; i < tfl.length; i++) {\n if(tfl[i].direction == 'outbound'){\n \tnextTrains.push({\n \t 'expected': (tfl[i].timeToStation)/60,\n \t 'destination': tfl[i].destinationName\n \t});\n } \n }\n }else{\n // no schedule received\n station = msg.stationid; // use station id as default\n nextTrains.push({\n 'expected': 0,\n \t'destination': \"Out of Service\"\n })\n }\n \n trains.station = station;\n trains.schedule = nextTrains;\n}\n\n// display and send schedule data\nconsole.log(\"outbound schedule new schema > \");\nconsole.log(util.inspect(trains, false, null));\nmsg.payload = trains;\nflow.set('trainschedule', msg.payload); // save for flow use\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":260,"wires":[["9e12935e.61ed7","e9321505.16cde8","54451966.abbae8","f628b4f.f09d748"]]},{"id":"b4b2a289.4b4d6","type":"mqtt out","z":"e60e9052.19f17","name":"","topic":"","qos":"","retain":"","broker":"b1d8d4eb.4e2728","x":615.5,"y":520,"wires":[]},{"id":"e9321505.16cde8","type":"function","z":"e60e9052.19f17","name":"Format to MQTT display string","func":"var station = msg.payload.station;\nvar schedule = msg.payload.schedule;\nvar destination;\nvar split;\nmsg.topic = \"/trainschedule/\" + msg.stationid;\n\nif (schedule[0].destination == \"Out of Service\"){\n destination = schedule[0].destination;\n //destination = \"Out of Service\";\n msg.payload = destination;\n return msg;\n}else{\n // Split the string and only use the first two words of each value\n split = station.split(\" \");\n station = split[0] +\" \"+ split[1] + \"\\n\\n\"; \n msg.payload = station;\n for(var x = 0; x < schedule.length; x++){\n split = schedule[x].destination.split(\" \");\n destination = split[0] +\" \"+ split[1];\n msg.payload += pad(schedule[x].expected) + \"m\" + \" \" + destination + \"\\n\";\n }\n return msg;\n}\n\n\nfunction pad(n) {\n return (n < 10) ? (\"0\" + n) : n;\n}","outputs":1,"noerr":0,"x":310.5,"y":493,"wires":[["b4b2a289.4b4d6","e1254324.1edac"]]},{"id":"f91fdd8f.06e02","type":"mqtt in","z":"e60e9052.19f17","name":"","topic":"#","broker":"b1d8d4eb.4e2728","x":88.5,"y":637,"wires":[["c5795b82.3a86a8"]]},{"id":"c5795b82.3a86a8","type":"debug","z":"e60e9052.19f17","name":"MQTT #","active":false,"console":"false","complete":"payload","x":247.5,"y":637,"wires":[]},{"id":"56e7e2e7.a9181c","type":"comment","z":"e60e9052.19f17","name":"Schedule Display","info":"","x":103,"y":434,"wires":[]},{"id":"a4e58e24.5b1a7","type":"comment","z":"e60e9052.19f17","name":"MQTT Monitor","info":"","x":95.5,"y":601,"wires":[]},{"id":"110734c1.eef8cb","type":"delay","z":"e60e9052.19f17","name":"","pauseType":"rate","timeout":"30","timeoutUnits":"seconds","rate":"1","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":260,"y":180,"wires":[["9a4a5cb0.65b5a"]]},{"id":"e1254324.1edac","type":"debug","z":"e60e9052.19f17","name":"MQTT Format","active":true,"console":"false","complete":"payload","x":640,"y":580,"wires":[]},{"id":"12aefeac.ed5101","type":"comment","z":"e60e9052.19f17","name":"MQTT topic /trainschedule/stationid","info":"stationid is inherited from inject","x":660,"y":460,"wires":[]},{"id":"54451966.abbae8","type":"ui_template","z":"e60e9052.19f17","tab":"e33ec540.1cc138","name":"Station","group":"Train Schedule","order":1,"format":"{{msg.payload.station}}\n<ul>\n <li ng-repeat=\"x in msg.payload.schedule\">\n {{ x.expected + 'min, ' + x.destination }}</li>\n</ul>\n","storeOutMessages":true,"fwdInMessages":false,"x":640,"y":300,"wires":[[]]},{"id":"51f23f28.ae0dc","type":"debug","z":"e60e9052.19f17","name":"Train Schedule request","active":true,"console":"false","complete":"payload","x":690,"y":60,"wires":[]},{"id":"76b2b9d5.894d48","type":"http in","z":"e60e9052.19f17","name":"","url":"/trainjson","method":"get","swaggerDoc":"","x":110,"y":760,"wires":[["d7a9c399.28564"]]},{"id":"c3072bfd.3cf8d8","type":"http response","z":"e60e9052.19f17","name":"","x":630,"y":760,"wires":[]},{"id":"d7a9c399.28564","type":"function","z":"e60e9052.19f17","name":"","func":"msg.payload = flow.get('trainschedule');\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":760,"wires":[["c3072bfd.3cf8d8"]]},{"id":"16456291.e9ba9d","type":"http in","z":"e60e9052.19f17","name":"","url":"/traindisplay","method":"get","swaggerDoc":"","x":120,"y":800,"wires":[["1ffadf81.e0052"]]},{"id":"aafb6bcf.550498","type":"http response","z":"e60e9052.19f17","name":"","x":630,"y":800,"wires":[]},{"id":"1ffadf81.e0052","type":"function","z":"e60e9052.19f17","name":"","func":"msg.payload = flow.get('trainschedule');\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":800,"wires":[["487678b9.b78988"]]},{"id":"487678b9.b78988","type":"template","z":"e60e9052.19f17","name":"Format Screen","field":"payload","fieldType":"msg","format":"handlebars","template":"{{payload.station}}\n<br>\n{{#payload.schedule}}\n {{expected}}min {{destination}}\n{{/payload.schedule}}\n\n\n","x":460,"y":800,"wires":[["aafb6bcf.550498"]]},{"id":"6f8011f5.907ff","type":"comment","z":"e60e9052.19f17","name":"API Access","info":"","x":90,"y":720,"wires":[]}]