Arduino Yun Process and HttpClient cause program stop

Hey there,
I'm using an Arduino Yun to control a clock. Everything works until the Arduino-Part of the Yun stops working (takes something between 30 mins or 12 hours) while executing one of those two functions. The second function (provides my clock with a time update) causes a fatal stop, while the first function (reads data from a website to switch clock on or off) only delays the execution of the program for about 30 seconds. Any Ideas how to solve the problem?

HttpClient client;
client.get("http://xxxxx/xxx/led.txt");

if (client.available() > 0) {
char c = client.peek();
}
client.flush();

Process date;

if (!date.running()) {
date.begin("date");
date.addParameter("+%D-%T");
date.run();
}

String timeString;

while (date.available() > 0) {
timeString = date.readString();
}

int firstColon = timeString.indexOf(":");
int secondColon = timeString.lastIndexOf(":");
int firstSlash = timeString.indexOf("/");
int minsign = timeString.indexOf("-");

String dayString = timeString.substring(firstSlash + 1, firstSlash + 3);
String hourString = timeString.substring(minsign + 1, firstColon);
String minString = timeString.substring(firstColon + 1, secondColon);
String secString = timeString.substring(secondColon + 1);

hours = hourString.toInt();
minutes = minString.toInt();
seconds = secString.toInt();
dzien = dayString.toInt();
setTime(hours, minutes, seconds, dzien, 00, 00);
date.flush();
date.close();

Any Ideas how to solve the problem?

Which problem? The fact that it takes time to process a client request is not a problem. It is a reality. If that it is the problem that you are trying to address, the solution it quite simple. Take the Arduino off the network. That way, clients won’t be able to connect to it, so there won’t be any pesky clients to deal with.

If there is some other problem, the fine folks at http://snippets-r-us.com will be able to help you with your snippets.

PS. RTCs are really cheap.

PPS: Pissing away resources on Strings is not a good idea.

Thanks @PaulS for the quick answer.

so why is it that the HttpClient takes in the beginning not even a second to get data and after one hour after starting the program 30 secs or more?

and why causes the process (which is responsible for getting a time update) a complete stop of the program after being already successfully called a few times?

so why is it that the HttpClient takes in the beginning not even a second to get data and after one hour after starting the program 30 secs or more?

A snippet of code calls for a snippet of an answer. The problem is that...

and why causes the process (which is responsible for getting a time update) a complete stop of the program after being already successfully called a few times?

I'm going to guess that it is because you are doing something wrong.

okay, the problems seems to be with the strings in the procedure using to much memory and causing the 328 to quit work.

any ideas how to synchronize time w/o utilizing strings ?

any ideas how to synchronize time w/o utilizing strings ?

You are not utilizing strings now, and that is causing you problems. You are using Strings.

Start using strings. The time and date information appears to be in a rather well defined format, so the maximum length is known. Define an array of that size (1 larger actually, to account for the NULL terminator). Use readBytesUntil() instead of readString().

Then, use string functions, like strstr(), strtok(), or even sscanf() to extract the useful data.

new function updating time without using strings: function works and program runs for about 5 minutes. after being called something between the 3rd and 6th time the function causes a complete failure of yun, wifi connection and 328 program execution. seems like there must be a problem with the bridge. please help!!!

void gettimefromlinux () {

Process date;

if (!date.running()) {
date.begin(“date”);
date.addParameter("+%D-%T");
date.run();
}

char zeitdaten[18];
while (date.available() > 0) {
for (int i = 0; i < 18; i++) {
zeitdaten = date.read();

  • }*
  • }*
    _ hours = (zeitdaten[9] * 10 + zeitdaten[10] - 528);_
    _ minutes = (zeitdaten[12] * 10 + zeitdaten[13] - 528);_
    _ seconds = (zeitdaten[15] * 10 + zeitdaten[16] - 528);_
    _ dzien = (zeitdaten[3] * 10 + zeitdaten[4] - 528);_
  • setTime(hours, minutes, seconds, dzien, 00, 00);*

}

Wouldn't this Thread be more appropriate for the Yun section of the Forum?

...R

Moved to Yún.

The date come from BusyBox is handicape

BusyBox v1.19.4 (2014-11-13 19:03:47 CET) multi-call binary.

Recognized TIME formats:
        hh:mm[:ss]
        [YYYY.]MM.DD-hh:mm[:ss]
        YYYY-MM-DD hh:mm[:ss]
        [[[[[YY]YY]MM]DD]hh]mm[.ss]

Install GNU date.

opkg update
opkg install coreutils-date

opkg files coreutils-date
Package coreutils-date (8.16-1) is installed on root and has the following files:

FORMAT controls the output. Interpreted sequences are:

 %%   a literal %
  %a   locale's abbreviated weekday name (e.g., Sun)
  %A   locale's full weekday name (e.g., Sunday)
  %b   locale's abbreviated month name (e.g., Jan)
  %B   locale's full month name (e.g., January)
  %c   locale's date and time (e.g., Thu Mar  3 23:05:25 2005)
  %C   century; like %Y, except omit last two digits (e.g., 20)
  %d   day of month (e.g., 01)
  %D   date; same as %m/%d/%y
  %e   day of month, space padded; same as %_d
  %F   full date; same as %Y-%m-%d
  %g   last two digits of year of ISO week number (see %G)
  %G   year of ISO week number (see %V); normally useful only with %V
  %h   same as %b
  %H   hour (00..23)
  %I   hour (01..12)
  %j   day of year (001..366)
  %k   hour, space padded ( 0..23); same as %_H
  %l   hour, space padded ( 1..12); same as %_I
  %m   month (01..12)
  %M   minute (00..59)
  %n   a newline
  %N   nanoseconds (000000000..999999999)
  %p   locale's equivalent of either AM or PM; blank if not known
  %P   like %p, but lower case
  %r   locale's 12-hour clock time (e.g., 11:11:04 PM)
  %R   24-hour hour and minute; same as %H:%M
  %s   seconds since 1970-01-01 00:00:00 UTC
  %S   second (00..60)
  %t   a tab
  %T   time; same as %H:%M:%S
  %u   day of week (1..7); 1 is Monday
  %U   week number of year, with Sunday as first day of week (00..53)
  %V   ISO week number, with Monday as first day of week (01..53)
  %w   day of week (0..6); 0 is Sunday
  %W   week number of year, with Monday as first day of week (00..53)
  %x   locale's date representation (e.g., 12/31/99)
  %X   locale's time representation (e.g., 23:13:48)
  %y   last two digits of year (00..99)
  %Y   year
  %z   +hhmm numeric time zone (e.g., -0400)
  %:z  +hh:mm numeric time zone (e.g., -04:00)
  %::z  +hh:mm:ss numeric time zone (e.g., -04:00:00)
  %:::z  numeric time zone with : to necessary precision (e.g., -04, +05:30)
  %Z   alphabetic time zone abbreviation (e.g., EDT)
/usr/bin/date  +%T
12:28:27
/usr/bin/date  "+%A %b %d %Y"
Friday Nov 06 2015

You have some very curious code constructs. And please use code tags when posting code: click the </> button, to insert the tags, then paste the code between them. It makes it much easier to read.

TobiasCrackz:

HttpClient client;

client.get(“http://xxxxx/xxx/led.txt”);

if (client.available() > 0) {
      char c = client.peek();
    }
    client.flush();

What are you trying to accomplish here? You make an HTTP request. Then, you look to see if there is any data returned: if so, you create a local variable, read a character, then throw away that character at the end of the IF block. Then you throw away the rest of the clients data when you flush it. Why bother peeking at a character if you don’t do anything with it?

Do you actually need to look at the result of the request? If so, what does the result normally look like, and what do you want to do if the response is not as expected? We can give you some further hints with more information.

TobiasCrackz:

void gettimefromlinux () {

Process date;

if (!date.running())  {
    date.begin(“date”);
    date.addParameter("+%D-%T");
    date.run();
  }

char zeitdaten[18];
  while (date.available() > 0) {
    for (int i = 0; i < 18; i++) {
      zeitdaten[i] = date.read();
    }
  }

hours = (zeitdaten[9] * 10 + zeitdaten[10] - 528);
  minutes = (zeitdaten[12] * 10 + zeitdaten[13] - 528);
  seconds = (zeitdaten[15] * 10 + zeitdaten[16] - 528);
  dzien = (zeitdaten[3] * 10 + zeitdaten[4] - 528);

setTime(hours, minutes, seconds, dzien, 00, 00);

}

I see multiple issues here.

First, you create a new Process object upon entry to the function (because it’s a local variable.) So why bother to check if it’s running as the first step - you can be sure it’s not.

Then, you start reading the result. You have a while characters available loop, and inside of that you have a loop that always reads 18 characters. If the Process returns exactly 18 characters, you are good. If it returns less than 18, the inner loop will block on the read() function once you run out of characters. If it returns more than 18 characters, the inner loop will complete, then the outer while loop will cycle again and the inner loop will try to read another 18 characters. This construct will tend to lock up if the return value is not an exact multiple of 18 characters.

Then, you go on to process the data. The code you have will work as long as the response is always exactly as you expect. What will happen if the above loop doesn’t give you the data you are expecting? You will try to convert the wrong characters.

Everything seems to be predicated on the command returning exactly 18 characters. The command you are using will give 17 characters, and I assume a newline at the end. So it should normally work, but the code is currently not tolerant of anything being different than expected. Good code design should be tolerant of invalid input. It’s entirely possible that sometimes the date command is giving you something different than expected, and that could cause problems with the current code. The hours/minutes/seconds/dzien values may be invalid – what will setTime do with values that are out of range?

A safer way to handle this is to make your character array long enough to hold the entire response, plus a trailing NULL character. You are using the Process.run() function to run the command, which is a blocking function - it will not return until the process is complete. So at that time, you know how many characters have been returned by looking a Process.available(). I suggest that you read that value, shorten it if necessary to prevent running over your character buffer, and then call Process.readBytes() to read in all of the data. Then perform some sanity checks to make sure you have the data you expect.

An example sketch:

#include <Bridge.h>
#include <Process.h>

int counter;

void setup()
{
    // Initialize the Bridge
    Bridge.begin();

    // Initialize the Serial port
    Serial.begin(9600);

    // Wait until a Serial Monitor is connected.
    while (!Serial);

    counter = 0;
}



void loop()
{
    Process date;

    Serial.print(++counter);
    Serial.print("  ");

    // Get the date from Linux
    date.begin("date");
    date.addParameter("+%D-%T");
    date.run();

    // Response should be of the form "MM/DD/YY-HH:MM:SS"
    // Room for 17 character response plus a NULL terminator
    char zeitdaten[18];

    // Get the number of characters available,
    byte len = date.available();
    if (len == 18)
    {
        // Got the expected number of characters, 17 plus a newline.
        // Read in the 17 characters, then NULL terminate the string.
        date.readBytes(zeitdaten, 17);
        zeitdaten[17] = '\0';

        // Print the received string.
        Serial.print(zeitdaten);

        // Sanity checks to look for a well formed response
        if (  (zeitdaten[2]  == '/')  &&
              (zeitdaten[5]  == '/')  &&
              (zeitdaten[8]  == '-')  &&
              (zeitdaten[11] == ':')  &&
              (zeitdaten[14] == ':')  )
        {
            // Extract the individual fields
            byte hours = (zeitdaten[9] * 10 + zeitdaten[10] - 528);
            byte minutes = (zeitdaten[12] * 10 + zeitdaten[13] - 528);
            byte seconds = (zeitdaten[15] * 10 + zeitdaten[16] - 528);
            byte dzien = (zeitdaten[3] * 10 + zeitdaten[4] - 528);

            // Print the decoded values
            Serial.print(" -- H:");
            Serial.print(hours);
            Serial.print(" M:");
            Serial.print(minutes);
            Serial.print(" S:");
            Serial.print(seconds);
            Serial.print(" D:");
            Serial.println(dzien);
        }
        else
        {
            Serial.println(" Wrong format!");
            // Error handling nere...
        }
    }
    else
    {
      Serial.print("Process returned ");
      Serial.print(len);
      Serial.println(" characters!");
        // Error handling here...
    }
}

I let this run through a couple thousand loops, and got no errors. However, if the time function did return something strange, there are enough checks in there that it should be caught and not cause a problem.

The code you have works, if the input is exactly right. But good code should work properly and not crash even if the input is not what is expected. You need to qualify your input data and make sure it is really formatted the way you expect it to be.

Move most business logic from ATmega32u4 to Atheros AR9331.

void loop()
{
  String firstline, secondline;
  //secondline /usr/bin/date  "+%A %b %d %Y" "Friday Nov 06 2015" from process object 
  lcd.clear();
  // JUMP TO CENTER ON A 16X2 SCREEN //
  lcd.setCursor(4,0);
  lcd.print(firstline);
  // NEXT LINE, 1 SPACE IN FROM THE LEFT //
  lcd.setCursor(1,1);
  lcd.print(secondline);
  delay(1000); // Wait 1 second
}

hey guys!!
thanks for so many tips, hints and even a complete sketch!! awesome :))

i finally solved the problem:

  1. eliminated all strings in gettimefromlinux and replaced them by arrays, test runs on that gave me 30 valid readouts in a second over a period of 24h!!!

  2. introduced delay(100); in the mainloop of the sketch in order to prevent it from doing too much work

  3. eliminated some “if” conditions, reducing the capabilities but hey, at least it works now

  4. had to delete the Http client because it caused a too big delay when asking for data from the website.

→ all in all it looks to me as if the program took to many resources of the atmel, so it just got stuck…

HttpClient client;
    client.get("xxxxxxxxx/tobi/led.txt");

    while (client.available() > 0) {

      char c = client.read();

      if (c == '1') {
        indi = 1;
      }
      if (c == '0') {
        indi = 0;
      }
      if (c == '2') {
        indi = 2;
      }

is there a way in implementing a validity check on the internet connection?

like this:

if (internet connection available) --> start http client and get information from website, else proceed in code and try next loop-run

TobiasCrackz:

      if (c == '1') {

indi = 1;
      }
      if (c == ‘0’) {
        indi = 0;
      }
      if (c == ‘2’) {
        indi = 2;
      }

   if ( (c >= '0') && (c <= '2') )
        indi = c - '0';

A little more efficient, and a little less code, but not as easily readable. Probably not worth the effort with two alternatives (0,1) and might not be worth the effort with three alternatives (0,1,2) but could make a difference if there are more – like if you were getting (0,1,2,3,4,5) as a response.

An alternative that keeps the same readability you have, but using else clauses:

      if (c == '1') {
        indi = 1;
      }
      else if (c == '0') {
        indi = 0;
      }
      else if (c == '2') {
        indi = 2;
      }

Without the else clauses, all three IF statements are evaluated every time, even if one of the earlier ones becomes true. With the else clauses, once an expression is true, the rest of them are skipped. When doing this, it’s best to put the most frequently seen cases first, so that the more obscure cases are only evaluated if the more common ones are false.

Using the else clauses allows one more else condition:

      if (c == '1') {
        indi = 1;
      }
      else if (c == '0') {
        indi = 0;
      }
      else if (c == '2') {
        indi = 2;
      }
      else {
        // do some error handling here
      }

This lets you do something special if you don’t get the expected response. Otherwise, to do the same sort of error checking, you would have to set indi to some invalid magic number (like -1 or 255) and then add yet another IF check to see if it still has the invalid value after this string of comparisons.

You could do the same sort of error catching else with the condensed version:

  if ( (c >= '0') && (c <= '2') )
      indi = c - '0';
  else
    // error handling here

TobiasCrackz:
is there a way in implementing a validity check on the internet connection?

Yes, you could run a Process object to query the network status and return that to your sketch. The Process object would make a call to a script on the Linux side (shell script, Lua code, Python code, etc) that would query the network status. As an example, look at the WiFi Status Example. This uses a Process object to run a Lua script named pretty-wifi-info.lua to get and format a bunch of WiFi information, and return it to the sketch. Rather than get all of that information back, and then parse through it in the sketch to find the connection status, it would make more sense to write a script on the Linux side that just returns the desired status, and call that script. Also, don’t forget that there is also the Ethernet port, you might want to check that status as well?

But now you have the sketch making a call to the Linux side to check the status, wait for a response, and then decode the response. Then you will make an HttpClient call to access a web resource, which again translates into a Linux call to actually perform the transfer. You are also going to the Linux side to read the date and time. That’s a lot of low-level communications between the sketch and the Linux side. This project sounds like a good candidate for doing most if not all of this logic on the Linux side (as sonnyyu mentions in reply #11.)

For example, you could have a sketch on the Linux side that checks if the network is connected, and if so make the HTTP request right there, process the results, and send the digested information back to the sketch. Then, you would use a Process object to call that one unified script and cut down on a lot of inter-processor communications and simplify the sketch. You could expand that to include your time based and other processing as well, and just run the Linux code asynchronously in the background.

The Linux side has a lot more resources than the sketch side: much more RAM, very much more code space, and it runs a lot faster. It makes sense to put as much logic as possible on the Linux side, and use the sketch to just handle the low level hardware I/O. It’s a different way of thinking than the usual Arduino sketch, but it makes a lot of sense and makes things much more powerful. You’ll be able to do a lot more with your Yun, and not run into:

→ all in all it looks to me as if the program took to many resources of the atmel, so it just got stuck…

Thank you guys for your effort and help!! awesome community!! :slight_smile: especially @ShapeShifter!!!!

now i will work myself through how-to-program-the-linux-side !!!!