Small Timetable with LED Matrix

Hi
I'm working on a small project to display actual time with date and two departure times from a online timetable.

Steps:
get time
get timetable information via curl
display time/date and two departures times

Also I have not so much program storage space left.
Sketch uses 28,080 bytes (97%) of program storage space. Maximum is 28,672 bytes.
Global variables use 863 bytes (33%) of dynamic memory, leaving 1,697 bytes for local variables. Maximum is 2,560 bytes.

here the code what I have right now:

#include <Process.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>

#define MAX_ZONES 2
#define ZONE_SIZE 5
#define  MAX_DEVICES (MAX_ZONES * ZONE_SIZE)

#define ZONE_UPPER  1
#define ZONE_LOWER  0

#define CLK_PIN   11
#define DATA_PIN  12
#define CS_PIN    10

MD_Parola P = MD_Parola(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

char dep1[8];
char dep2[8];
int seconds;
int lastSecond = -1;
String timeStamp;
String dateStamp;
String ts;

Process pc;    // process for curl, used to get timetable information
Process date;  // process used to get time

void setup() {
  Bridge.begin();  // Initialize Bridge
  Serial.begin(57600);
  while (!Serial);
  Serial.println("Start Setup");
  P.begin(MAX_ZONES);
  P.setZone(ZONE_LOWER, 0, ZONE_SIZE - 1);
  P.setZone(ZONE_UPPER, ZONE_SIZE, MAX_DEVICES - 1);
  Serial.println("End Setup");
}

void loop() {
  getTime();
  getDepartures();
  toMatrix();
}






String urlDecode(String urlChars) {
  urlChars.replace("[", "%5B");
  urlChars.replace("]", "%5D");
  urlChars.replace("ä", "%C3%A4");
  return urlChars;
}

void getDepartures() {
  char jsonResponse[200];

  String url = "http://transport.opendata.ch/v1/connections?from=Kräyigen&to=Bern&limit=2&fields[]=connections/from/departure&time=" + ts;
  Serial.println(url);

  pc.begin("curl");
  pc.addParameter(" - H \"Cache-Control: no-cache\"");
  pc.addParameter(urlDecode(url));
  pc.run();
  // response
  int i = 0;
  while (pc.available() > 0) {
    char c = pc.read();
    jsonResponse[i] = c;
    i++;
  }

  char *ptr;      // temp pointers
  char *fieldPtr; // temp pointers

  // get departure time 1
  ptr = strstr(jsonResponse, "T");
  if (ptr != NULL) {
    ptr++;
    fieldPtr = ptr;
    ptr = strstr(ptr, "+");
    ptr = '\0';
    strcpy(dep1, "1. ");
    strncat(dep1, fieldPtr, 5);
  }

  // get departure time 2
  ptr = strstr(fieldPtr, "T");
  if (ptr != NULL) {
    ptr++;
    fieldPtr = ptr;
    ptr = strstr(ptr, "+");
    ptr = '\0';
    strcpy(dep2, "2. ");
    strncat(dep2, fieldPtr, 5);
  }
}

void getTime() {
  Serial.println("get time ...");
  if (lastSecond != seconds) {
    if (!date.running()) {
      date.begin("date");
      date.addParameter("+%d.%m.%y %T");
      date.run();
    }
  }

  while (date.available() > 0) {
    timeStamp = date.readString();
    timeStamp.trim();
    dateStamp = timeStamp.substring(0, 8);
    timeStamp = timeStamp.substring(9, 17);
    int secondColon = timeStamp.lastIndexOf(":");
    String secString = timeStamp.substring(secondColon + 1);
    lastSecond = seconds;
    seconds = secString.toInt();
    ts = timeStamp.substring(0, 5);   // timestamp needed for curl query
  }
}

void toMatrix() {
  char charBuf[6];
  ts.toCharArray(charBuf, 6);

  P.displayZoneText(ZONE_LOWER, charBuf, CENTER, 40, 5000, SCROLL_DOWN, SCROLL_UP);
  P.displayZoneText(ZONE_UPPER, dep1, CENTER, 40, 5000, SCROLL_DOWN, SCROLL_UP);

  // synchronise the start and run the display to completion
  P.synchZoneStart();
  while (!P.getZoneStatus(ZONE_LOWER) || !P.getZoneStatus(ZONE_UPPER))
    P.displayAnimate();

  char charBuf2[9];
  dateStamp.toCharArray(charBuf2, 9);

  P.displayZoneText(ZONE_LOWER, charBuf2, CENTER, 40, 5000, SCROLL_UP, SCROLL_DOWN);
  P.displayZoneText(ZONE_UPPER, dep2, CENTER, 40, 5000, SCROLL_UP, SCROLL_DOWN);

  // synchronise the start and run the display to completion
  P.synchZoneStart();
  while (!P.getZoneStatus(ZONE_LOWER) || !P.getZoneStatus(ZONE_UPPER))
    P.displayAnimate();
}

The time/data part is working. The curl part itself is also working.
I have some problem with read out of the departure times.

Curl is running the url and the response is as follows:

{
	"connections": [{
		"from": {
			"departure": "2016-01-05T15:53:00+0100"
		}
	}, {
		"from": {
			"departure": "2016-01-05T15:54:00+0100"
		}
	}]
}

from this json I need just the timestamp ->15:53 and 15:54

When I upload the whole sketch noting will display on the LED Matrix. When I uncomment the block

 // get departure time 1
...

and

  // get departure time 2
...

then the time and date on the LED matrix is shown.

Some one has an idea how to optimize the part to read out the time?

THX
Pascal

Move most business logic from Arduino to Linux!

nano /mnt/sda1/curljson.py
#!/usr/bin/python
import json
from datetime import datetime
from pprint import pprint
#import urllib2
#jsonobj = urllib2.urlopen('http://site.com/data.json')
#data = json.load(jsonobj)
jsonstr = """ {
        "connections": [{
                "from": {
                        "departure": "2016-01-05T15:53:00+0100"
                }
        }, {
                "from": {
                        "departure": "2016-01-05T15:54:00+0100"
                }
        }]
}"""
data = json.loads(jsonstr)
#pprint(data)
departure1=data["connections"][0]["from"]["departure"][11:19]
departure2=data["connections"][1]["from"]["departure"][11:19]
nowstr=datetime.now().strftime('%Y-%m-%d %H:%M:%S')
outputstr=nowstr+","+departure1+","+departure2
print outputstr
chmod 755 /mnt/sda1/curljson.py

Test code without Arduino!

root@Arduino:~# /mnt/sda1/curljson.py
2016-01-05 17:28:26,15:53:00,15:54:00

Yun & compatible support A to Z programming languages.
I use python here just for example. Feel free to use any.

18 Languages Supported

Arduino code:

#include <Process.h>
void setup() {
 Bridge.begin();  // Initialize Bridge
}
void loop() {
 Process p;              
 p.begin("/mnt/sda1/curljson.py");      
 while (p.running());
 while (p.available()) {
    char c = p.read();
    Serial.print(c);
 }
 delay(1000); 
}

Process Class with Return Variable

ahh OK, Cool idea. I will try to implement that.
THX.

Here also my result:

#include <Process.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>

#define MAX_ZONES 2
#define ZONE_SIZE 5
#define  MAX_DEVICES (MAX_ZONES * ZONE_SIZE)

#define ZONE_UPPER  1
#define ZONE_LOWER  0

#define CLK_PIN   11
#define DATA_PIN  12
#define CS_PIN    10

MD_Parola P = MD_Parola(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

char dep1[10];
char dep2[10];
int seconds;
int lastSecond = -1;
String timeStamp;
String dateStamp;

void setup() {
  Bridge.begin();  // Initialize Bridge
  P.begin(MAX_ZONES);
  P.setZone(ZONE_LOWER, 0, ZONE_SIZE - 1);
  P.setZone(ZONE_UPPER, ZONE_SIZE, MAX_DEVICES - 1);
}

void loop() {
  getTime();
  getDepartures();
  toMatrix();
}

void getDepartures() {
  int i = 0;
  char jsonResponse[15];
  char *ptr;
  Process p;
  p.runShellCommand("/mnt/sda1/arduino/www/timetable/curl.php");
  while (p.running());
  while (p.available()) {
    char c = p.read();
    jsonResponse[i] = c;
    i++;
  }

  ptr = strtok(jsonResponse, ","); // get first time
  strcpy(dep1, "1. ");
  strncat(dep1, ptr, 6);
  ptr = strtok(NULL, ",");         // get second time
  strcpy(dep2, "2. ");
  strncat(dep2, ptr, 6);
}

void getTime() {
  Process date;  // process used to get time
  if (lastSecond != seconds) {
    if (!date.running()) {
      date.begin("date");
      date.addParameter("+%d.%m.%y %T");
      date.run();
    }
  }

  while (date.available() > 0) {
    timeStamp = date.readString();
    timeStamp.trim();
    dateStamp = timeStamp.substring(0, 8);
    timeStamp = timeStamp.substring(9, 17);
    int secondColon = timeStamp.lastIndexOf(":");
    String secString = timeStamp.substring(secondColon + 1);
    lastSecond = seconds;
    seconds = secString.toInt();
}

void toMatrix() {
  char charBuf[6];
  timeStamp.toCharArray(charBuf, 6);

  P.displayZoneText(ZONE_LOWER, charBuf, CENTER, 40, 5000, SCROLL_DOWN, SCROLL_UP);
  P.displayZoneText(ZONE_UPPER, dep1, CENTER, 40, 5000, SCROLL_DOWN, SCROLL_UP);

  // synchronise the start and run the display to completion
  P.synchZoneStart();
  while (!P.getZoneStatus(ZONE_LOWER) || !P.getZoneStatus(ZONE_UPPER))
    P.displayAnimate();

  char charBuf2[9];
  dateStamp.toCharArray(charBuf2, 9);

  P.displayZoneText(ZONE_LOWER, charBuf2, CENTER, 40, 5000, SCROLL_UP, SCROLL_DOWN);
  P.displayZoneText(ZONE_UPPER, dep2, CENTER, 40, 5000, SCROLL_UP, SCROLL_DOWN);

  // synchronise the start and run the display to completion
  P.synchZoneStart();
  while (!P.getZoneStatus(ZONE_LOWER) || !P.getZoneStatus(ZONE_UPPER))
    P.displayAnimate();
}

and on /mnt/sda1/arduino/www/timetable/

my curl.php

#!/usr/bin/php-cli
<?php

date_default_timezone_set("Europe/Zurich");
$time = date("H:i");

$resources = 'connections';

$data = array(
    'from' => 'Kräyigen',
    'to' => 'Bern',
    'limit' => '2',
    'fields[]' => 'connections/from/departure',
    'time' => $time);

$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_AUTOREFERER, 1);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_HTTPGET, 1);
curl_setopt($curl, CURLOPT_URL, "http://transport.opendata.ch/v1/" . $resources . "?" . http_build_query($data));
if ($response = curl_exec($curl)) {
    $size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
    $body = substr($response, $size);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
}
@curl_close($curl);

$json = json_decode($body, true);
$time1 = substr($json['connections'][0]['from']['departure'], 11, 5);
$time2 = substr($json['connections'][1]['from']['departure'], 11, 5);

if ($httpCode == 200) {
    print $time1;
    print ",";
    print $time2;
} else {
    print "error";
    print ",";
    print "curl!";
}

?>

be sure, the code could more optimized

THX sonnyyu for that hint.

The python and php are OK for POC (Proof of concept) only.

But,

Seriously, this is embedded stuff, at some point you have to deal with low level languages, be it scripts, C or uncommon languages like Lua.

Jow, one key developer of Openwrt.

https://forum.openwrt.org/viewtopic.php?pid=275923#p275923

The four languages are left on the plate - Assembly Language, C/C++, Lua, Bash.

  • Move most business logic from Arduino to Linux!
  • Test code without Arduino!
  • Coding at: Assembly Language, Bash, C/C++, Lua.