Rest API gets slower and slower and finally webserver hangs...

Hello,

I'm working on a project with an arduino Yun.

A temperature sensor is connected by I2C to the mcu and my sketch pulls the temperature value every 10 seconds (by a Bridge.put call). I've also created a web page that make asynchronous calls to the REST api by ajax (http://localip/data/get) : it updates a content every 2 seconds. the calls from the webpage starts witha delay of 500ms (already pretty slow on a local network) and I let this page running, the calls gets slower and slower (above 3s and more).

And if Iwait enough, the webserver hangs. It can only be recovered by unplugging the board (no software reboot or reset button works).

Can someone has the same problem or can help me?
regards,

O.Boesch

Could it be an already fixed but not yet released issue with Bridge? Can you try using one of the nightly build of the IDE? http://arduino.cc/en/Main/Software#toc4

I already tried the last nightly build and nothing changes. It's not a great surprise to me since my sketch works well but the problem seems to be on linino. maybe something wrong with the rest api that makes the server hangs (sometimes no response at all, sometimes internal server error/500) ?

O Boesch

news about this problem:
when I call http://yunip/data/get the server answers :
Session data invalid! stack traceback:

: in function 'assert' ?: in function 'read' ?: in function 'reap' ?: in function 'dispatch' ?: in function <?:194>

any idea?

olivb, any progress with your issue? I'm experiencing what may be a similar problem.

I have a very simple HTTP client sketch sending data every 10 seconds, it runs fine for long periods of time (> 1 day) and then suddenly stops completely.

I'm considering to have some kind of watchdog involved to overcome the problem but with so many resets on the Yun I don't know where to start.

Federico, I would appreciate any hints from you side.

Cheers!

I'm sorry to say that it shouldn't happen and that I have no idea how to reproduce the issue.
With yun out-of-the-box configuration, uhttpd accepts only two concurrent http requests. The (lua) code that connects to the Bridge has a 5 seconds timeout. So it shouldn't directly related to the http part of your project

My only guess is that something is eating up RAM, so dealing with your REST requests is harder and harder as time passes, until there is no more ram left and the REST requests are dropped.

Can you describe in details the composition of your project? (I mean the sketch and any additional software and hardware it uses)

My goal is to make an automation of a swimming pool (light, pump,...). There are two hardwares : An IPX800v3 from gce electronics and a yun equiped with and lcd shield from sparkfun and a DS1621 (temperature sensor via I2C).


A functionnal diagram is given as attachment...


and here is the code of the sketch (not finished yet but the temperature is sent to the bridge...):

/*---------------------------------------------------------------------------------------------------------------------
  BelPoolConsole - Arduino Side
  Author : Olivier Boesch
  date : nov 2013
---------------------------------------------------------------------------------------------------------------------*/
//-- Mode debug (uncomment to debug)
//#define DEBUG_BELPOOL

//-- Librairies
#include <Wire.h>
#include <LiquidCrystal.h>
#include <TimedEvent.h>
#include <ButtonEvent.h>
#include<MenuBackend.h>
#include <Bridge.h>
#ifdef DEBUG_BELPOOL
  #include <Console.h>
#endif

//-- Led d'activité
#define ACT_LED 13

//-- Boutons
#define NUM_KEYS 5
int adc_key_val[5] ={50, 200, 400, 600, 800 };

//-- Sonde de temperature (adresse et mise a jour)
#define DS1621 (0x90 >> 1)
#define TAIR_UPDATE_TIME 10000 //mise a jour de Tair toutes les 10 secondes

//-- Lcd
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#define BACKLIGHT_PIN 10

//-- Menu
MenuBackend menu = MenuBackend(menuUse, menuChange);
  MenuItem miVolet = MenuItem(menu,"Volet",1);
    MenuItem miDeverVolet = MenuItem(menu, "Deverr. Volet",2);
    MenuItem miVerVolet = MenuItem(menu, "Verr. Volet",2);
  MenuItem miLumiere = MenuItem(menu, "Lumiere",1);
    MenuItem miLumiereOn = MenuItem(menu, "Lumiere Mar For",2);
    MenuItem miLumiereOff = MenuItem(menu, "Lumiere Arr For",2);
    MenuItem miLumiereAuto = MenuItem(menu, "Lumiere Auto",2);
  MenuItem miFiltration = MenuItem(menu, "Filtration",1);
    MenuItem miFiltrationDebor = MenuItem(menu, "Filt. Debord...",2);
    MenuItem miFiltrationFond = MenuItem(menu, "Filt. Fond...",2);
  MenuItem miPompe = MenuItem(menu, "Pompe",1);
    MenuItem miPompeOn = MenuItem(menu, "Pompe Mar For",2);
    MenuItem miPompeOff = MenuItem(menu, "Pompe Arr For",2);
    MenuItem miPompeAuto = MenuItem(menu, "Pompe Auto",2);
  MenuItem miSysteme = MenuItem(menu, "Systeme",1);
    MenuItem miSystemeRedemCent = MenuItem(menu, "Redem. Centrale",2);
    MenuItem miSystemeRedemConsole = MenuItem(menu, "Redem. Console",2);
    MenuItem miSystemeRedemControlleur = MenuItem(menu, "Redem Controll.",2);
    
//---- menu utilisé
void menuUse(MenuUseEvent used){
}

void menuChange(MenuChangeEvent changed){
}
  
//---- Setup de l'arduino
void setup(){
  pinMode(BACKLIGHT_PIN,OUTPUT);
  pinMode(ACT_LED,OUTPUT);
  pinMode(A5,INPUT);
  digitalWrite(ACT_LED,HIGH);
  Bridge.begin();
  #ifdef DEBUG_BELPOOL
    Console.begin();
    while (!Console); // Attente de connection de la console.
  #endif
  #ifdef DEBUG_BELPOOL
    Console.println("Demarrage de BelPoolConsole...");
  #endif
  buttons_setup();
  lcd_setup();
  menu_setup();
  ds1621_setup();  
  TimedEvent.addTimer(TAIR_UPDATE_TIME,Tair_event);
  Tair_event(NULL); //force mise a jour de Tair des le debut
  digitalWrite(BACKLIGHT_PIN,HIGH);
  digitalWrite(ACT_LED,LOW);
}

//---- Configuration des boutons
void buttons_setup(){
  //buffer initial pour 5 boutons
  ButtonEvent.initialCapacity = sizeof(ButtonInformation)*5;
  //Bouton droit
  ButtonEvent.addButton(0,        //analog button pin
                        0,  //analog value
                        50,       //deviation
                        onDownBtnRight,   //onDown event function
                        NULL,
                        NULL,
                        1000,
                        NULL,
                        400);

  //Bouton haut
  ButtonEvent.addButton(0,        //analog button pin
                        145,  //analog value
                        50,       //deviation
                        onDownBtnUp,   //onDown event function
                        NULL,
                        NULL,
                        1000,
                        NULL,
                        400);
  //Bouton bas
  ButtonEvent.addButton(0,        //analog button pin
                        329,  //analog value
                        50,       //deviation
                        onDownBtnDown,   //onDown event function
                        NULL,
                        NULL,
                        1000,
                        NULL,
                        400);
  //Bouton gauche
  ButtonEvent.addButton(0,        //analog button pin
                        505,  //analog value
                        50,       //deviation
                        onDownBtnLeft,   //onDown event function
                        NULL,     //onUp event function
                        onHoldBtnLeft,   //onHold event function
                        1000,             //hold time in milliseconds
                        NULL,
                        400);     
  //Bouton select
  ButtonEvent.addButton(0,        //analog button pin
                        741,  //analog value
                        50,       //deviation
                        onDownBtnSelect,   //onDown event function
                        NULL,
                        NULL,
                        1000,             //hold time in milliseconds
                        NULL,
                        400);
}

void onDownBtnRight(ButtonInformation* Sender) {
  #ifdef DEBUG_BELPOOL
    Console.println("Bouton Droit");
  #endif
}

void onDownBtnLeft(ButtonInformation* Sender) {
  #ifdef DEBUG_BELPOOL
    Console.println("Bouton Gauche");
  #endif
}

void onDownBtnUp(ButtonInformation* Sender) {
  #ifdef DEBUG_BELPOOL
    Console.println("Bouton Haut");
  #endif
}

void onDownBtnDown(ButtonInformation* Sender) {
  #ifdef DEBUG_BELPOOL
    Console.println("Bouton Bas");
  #endif
}

void onDownBtnSelect(ButtonInformation* Sender) {
  #ifdef DEBUG_BELPOOL
    Console.println("Bouton Select");
  #endif
}

void onHoldBtnLeft(ButtonInformation* Sender) {
  #ifdef DEBUG_BELPOOL
    Console.println("Bouton Gauche Long");
  #endif
}



//---- Configuration des menus de l'ecran LCD
void menu_setup(){
  #ifdef DEBUG_BELPOOL
    Console.print("Setup Menu...");
  #endif
  //menu.getRoot()
    //.onChangeTo(display_idle)
    //.add(miVolet);
  #ifdef DEBUG_BELPOOL
    Console.println("Ok");
  #endif
}

//---- Configuration de l'ecran LCD
void lcd_setup(){
  #ifdef DEBUG_BELPOOL
    Console.print("Setup Lcd...");
  #endif
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("BelPool v1.0");
  lcd.setCursor(0,1);
  lcd.print("    Demarrage");
  delay(1000);  
  #ifdef DEBUG_BELPOOL
    Console.println("Ok");
  #endif
}

//---- Configuration du DS1621
void ds1621_setup(){
  #ifdef DEBUG_BELPOOL
    Console.print("Setup DS1621...");
  #endif
  Wire.begin();
  Wire.beginTransmission(DS1621);           // connect to DS1621 (#0)
  Wire.write(0xAC);                          // Access Config
  Wire.write(0x02);                          // set for continuous conversion
  Wire.endTransmission();
  delay(50);
  Wire.beginTransmission(DS1621);           // restart
  Wire.write(0xEE);                          // start conversions
  Wire.endTransmission();
  #ifdef DEBUG_BELPOOL
    Console.println("Ok");
  #endif
}

//---- Lecture de la temperature sur le DS1621
float ds1621_read(){
  #ifdef DEBUG_BELPOOL
    Console.print("Lecture DS1621...");
  #endif
  float temp = 0.;
  Wire.beginTransmission(DS1621);
  //lecture de temperature
  Wire.write(0xAA);
  Wire.endTransmission();
  //demande de 2 octets
  Wire.requestFrom(DS1621, 2);
  //partie entiere de la temperature
  temp = (float)((int)(Wire.read()));
  //ajout de 0.5 deg au besoin
  if(Wire.read()) temp+=0.5;
  #ifdef DEBUG_BELPOOL
    Console.print("Tair: ");
    Console.print(temp);
    Console.println(" deg C");
  #endif
  return temp;
}

//---- Evenement de lecture du DS1621
void Tair_event(TimerInformation* Sender){
  //lecture du DS1621 et ecriture sur le bridge REST
  digitalWrite(ACT_LED,HIGH);
  Bridge.put("Tair",String(ds1621_read()));
  digitalWrite(ACT_LED,LOW);
}
//---- Fonction de Boucle
void loop(){
  TimedEvent.loop();  //timers
  ButtonEvent.loop(); //boutons
  //messages_loop();    //messages de la mailbox
}

Federico, in my case the program reads the wind speed and direction from an Sparkfun weather station (Weather Meter Kit - SEN-15901 - SparkFun Electronics) and sends a request to a Web server to display the data.

If you want to run the program use W2S26 as your Yun's name and see the post on http://wind2surf.com/ choosing Torino, Italy as your "Praia" (beach). (you don't need to have a weather station...)

Let me know what you find out.

Thanks

.

Wind2Surf_YunV3.zip (3.99 KB)

I have the same problem.
with Yun out of the box , i run Bridge example without modifications.
I can connect to Yun via Web browser and call http://192.168.0.22/arduino/digital/13/1

Then i set the GET request to Youn from extenal program like curl and call this request with 500ms time inteval.
After some time I don't get response from Yun,
When i call http://192.168.0.22/arduino/digital/13/1 via Web Browser again i get:
Session data invalid!
stack traceback:

: in function 'assert'
	?: in function 'read'
	?: in function 'reap'
	?: in function 'dispatch'
	?: in function <?:194>

It is clear Yun config and clear Bridge sketch.
I set password option in Yun's Rest config.

i have the same Problem

i work on a Aquarium light controll.
For this i build a sql database to write the the set values from a php webpage on linino ( works fine )
Now a cron job reads every minute the values from the sql database and write it with bridge put into the arduino.
The Arduino reads the values with bridge get to controll the lights.
Everything works fine for a while.
But after a few houres the linino webconnection hangs
so the php webpage on linino is not accessible and the wifi connection to linino do not work at all.
So i have to setup the linino wifi complete new and ressart the arduino board with power off.
Afterwards it works to for the next hours, and so on.
Any idea ?

Hello,

Could this be a problem of memory management of python ?
Because if don't make repetitive calls to the bridge for about 1h, everything seems to be ok again.

Hi,
It looks similar in my case.
The slow down isn't only ralated to REST, when I try to login via ssh, reponse is olaso very slow.
I was doing some tests with wired connection and at first it looked like the problem was only on WIFI, but
after some time like an hour or two, the 'slow down' apeared again.

Olivb, at least in my case your theory

memory management of python

doesn't apply. I'm not using Python, just plain Arduino C code and another thing to point out is the fact that the problem occurs without a timing pattern. Sometimes the Yun stops after a few hours and now it has been working for 3 days.

Any ideas how to deal with this problem.....

This is really annoying,
this makes the yun nearly senseless.
On Arduinos side is too less Memory for extensive projekt
so we have to go on lininos side,
but if the communication do not work i see no way for use.
I think it is very important to solve this problem.

OttoF, have you tried your scenario of communication with the Arduino sketch without using Bridge?
Is this unstable too?

BTW: I moved to direct Serial1 communication without using Bridge and this dropped memory consumption for my sketch from 22 KB to 11 KB, leaving much more bytes left for doing Arduino sketch kind of work.

How does communication between arduino sketch and php work?
I will test it.
But that doesn't solve the problem with bridge, I would prefer to have a solution for the bridge.
It is a part of arduino and all user have this problem.
I do some tests with my projekt and it seems to be a problem on the bridge lib on arduinos side.
A simple test with an digital input what direkt sets an digital output works slower and slower
(a led on the pin needs secondes to be on or off )
and at the same time a simple bridge.put of this digital out works not longer,
the php webside works ok, but the bridge.get for the d.out have no value.

What makes you think it is an issue with the Bridge as such? In all the examples mentioned before some webserver seems to be involved. I have an application where I would need to use the bridge a lot to communicate between Linino python and the sketch. Would this also experience this slowdown?

I will maybe make a test setup to use the bridge to send messages every second and see what happens...

Hi,

I had a similar problem. I have a sqlite database on the linino side, and the sketch is accesing every 30 seconds the database to write temperature values, doing curl calls and to php wichs acts as webservice.

Then I have an android app wichs querys the sqlite database using the same php script. I was curious about the linino web server capacity, and I deployed the android app to more devices and decreased the delay from the sketch execution from 30 seconds to 3 (just for a stress test).

With two clients (the sketch and the android app), all worked well. With three clients all worked well most of the time, because the clients are doing querys randomly and don't collide often.

But when two or more request from the clients to the php script collide, then all stops. I have to manually restart the uhhtpd to get it working again.

The solution was to increase the maximum number of concurrent requests in the web server configuration file. In my case, it is enough with 4... Maybe this helps

Bye

I would like to share my observations on that topic:
I moved from using Bridge to do a direct Serial1 communication between Arduino and Lininio. That works very well except that my Arduino sketch received the request with a delay of 2-3 s (!). I did measurements to be sure it is not because of the tornado WebSockets I use.
I changed my Arduino sketch from using "serialEvent1()" to using the main loop. And voila! Communication delays only for approximately 50ms. Looks like the only stable and fat way is the one shown in YunSerialTerminal.
As far as I know, Bridge uses Serial1. And maybe it also uses serialEvent1 to get notified for incoming data?