arduino - xively ogni 2/3gg si blocca il refresh dei dati su xively...perché?

Ho il seguente sketch che mi monitorizza l'impianto fotovoltaico e termosolarle.
Il tutto è visibile su: https://xively.com/feeds/281717909

Il mio problema è che ogni 2/3gg benchè arduino continui ad inviare i dati ( i led della scheda ethernet lampeggiano...) xively non ki aggiorna i grafici. Devo spegnere e riaccendere arduino e router che ho in casa. Mi sapete aiutare ad individuare il problema?
Grazie

Prima parte:

/* IDE 1.05

29/08/2013 V3  

CONTROLLO POTENZA GENERATA DAI PANNELLI FOTOVOLTAICI
CONTROLLO CONSUMI IN CASA
CONTROLLO ACCENSIONE E SPEGNIMENTO CALDAIA CON SENSORE LM35 POSIZIONATO SUL TUBO DELL'ACQUA CHE ESCE DAL BOLLITORE DEL SOLARE TERMICO
CONTROLLO TEMPERATURA ACQUAL ALL'INTERNO DEL BOLLITORE DEL SOLARE TERMICO
CONTROLLO ACCENSIONE E SPEGNIMENTO VENTOLA DI ASPIRAZIONE
CONTROLLO TEMPERATURA IN CENTRALE TERMICA
CONTROLLO TEMPERATURA ACQUA IN INGRESSO DEL BOLLITORE DEL SOLARE TERMICO
CONTROLLO ACCENSIONE RESISTENZA DA 2KW COMANDATA DA CENTRALINA IMPIANTO FOTOVOLTAICO


Ethernet shield attached to pins 10, 11, 12, 13
Arduino uno
modified by Ettore Massimo Albani
*/

#include <SPI.h>
#include <Ethernet.h>
#include "EmonLib.h"  // Include Emon Library
EnergyMonitor emon1;  // Create an instance CORRENTE GENERATA DAL FOTOVOLTAICO
EnergyMonitor emon2;  // Create an instance CORRENTE CONSUMATA IN CASA

#define APIKEY         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"   // replace your Cosm api key here
#define FEEDID         xxxxxx                     // replace your feed ID
#define USERAGENT      "xxxxxxxxxxxxxxxxxxxxxxxx"         // user agent is the project name

byte mac[] = {0xDE, 0xBD, 0xCC, 0xEF, 0xFE, 0xBD};// MAC address of Ethernet controller
IPAddress ip(192, 168, 1, 22);  // IP address on your network here
EthernetClient client;   // initialize the library instance:

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:

// IPAddress server(216, 52, 233, 121);   // numeric IP for api.cosm.com
char server[] = "api.cosm.com";    // name address for Cosm API
unsigned long lastConnectionTime = 0;  // last time you connected to the server, in milliseconds
boolean lastConnected = false;       // state of the connection last time through the main loop
const unsigned long postingInterval = 10000;  // delay between updates to Cosm.com (10 s)
String DataString = "";     // stringa per invio dati
char Buffer[10];            // buffer per dftostr()

int otherSensorReadingAria = 0;  
int otherSensorReadingCaldaia = 0;
int otherSensorReadingResistenza2Kw = 0;

int caldaiaON = 0;    //*INGRESSO digitale PER CONTROLLO WEB STATO CALDAIA 
int Ventola = 0;      //*INGRESSO digitale PER CONTROLLO WEB STATO VENTOLA
int Resistenza = 0;   //*INGRESSO digitale PER CONTROLLO WEB STATO resistenza

const float AnaRef = 5.0;            // valore tensione (5V)
const unsigned int Risoluzione = 1024;    // risoluzione (10 bit) 
const float RangeMin = 2.0; // temperatura minima °C sensore LM35DZ (alim. 5V, out con res. 2k in serie)
const float RangeMax = 100.0;  // temperatura massima °C sensore LM35DZ (alim. 5V, out con res. 2k in serie)
const float Incremento = 0.01;  // incremento (10 mV/°C)
float Volt = 0;       // valore sensori analogici in volt
const float Isteresi = 1.0; // isteresi (1 °C)
float TempAria = 0.0;   // temperatura aria
float TempAriaMin = 2.0;  // soglia inferiore temperatura aria (min 2 °C = RangeMin)
float TempAriaMax = 30.0; // soglia superiore temperatura aria (max 100 °C = RangeMax)
float TempAcquaOUTtermosolare = 0.0;   // temperatura acqua
float TempAcquaMin = 2.0;   // soglia inferiore temperatura acqua (min 2 °C)
float TempAcquaMax = 43.0;   // soglia superiore temperatura acqua (max 100 °C)
float TempAcquaINGtermosolare = 0.0; // temperatura acqua in ingresso al termosolare

extern unsigned long timer0_millis;
float mela;

void setup() {
  mela=1;
  analogReference(DEFAULT);        // DEFAULT (5V), INTERNAL (1,1V), EXTERNAL (0÷5V)

  pinMode(A0, INPUT);    // sensore di temperatura aria
  pinMode(A1, INPUT);    // sensore di temperatura acqua
  pinMode(A2, INPUT);    // sensore di temperatura acqua ingresso termosolare
  pinMode(A3, INPUT);    // TA Fotovoltaico
  pinMode(A4, INPUT);    // TA Casa
  
  pinMode(2, OUTPUT);    // D2 uscita per relè in parallelo alla resistenza da 2Kw installata sul bollitore 
  pinMode(3, INPUT);     //*D3 ingresso controllo stato ventola da D5   
  pinMode(4, INPUT);     //*D4 ingresso controllo stato caldaia da D6
  pinMode(5, OUTPUT);    //*USCITA IN PARALLELO AL RELE CALDAIA PER VISUALIZZAZIONE WEB STATO VENTOLA   
  pinMode(6, OUTPUT);    //*USCITA IN PARALLELO AL RELE ACQUA PER VISUALIZZAZIONE WEB STATO CALDAIA  
  pinMode(7, OUTPUT);     // relay ventola ON/OFF
  pinMode(8, OUTPUT);     // relay caldaia ON/OFF
  pinMode(9, INPUT);      // D10 ingresso per relè in parallelo alla resistenza da 2Kw installata sul bollitore

  Serial.begin(9600);
  
   emon1.current(3, 111.1);  // Potenza: A3 -POTENZA GENERATA DAL FOTOVOLTAICO-  input pin, calibration.
   emon2.current(4, 111.1);  // Potenza: A4 -POTENZA CONSUMATA IN CASA-  input pin, calibration.

  if (Ethernet.begin(mac) == 0) {     // start the Ethernet connection
    Ethernet.begin(mac, ip);          // DHCP failed, so use a fixed IP address
    Serial.println(F("Failed to configure Ethernet using DHCP"));
  }   
}

Seconda parte:

void loop() {
  
    double Produzione_Energia = emon1.calcIrms(1480);  // Calculate Irms only
    double Consumo_Energia = emon2.calcIrms(1480);  // Calculate Irms only
    
     Serial.print(F("Potenza Generata dal FV Kw: "));
     Serial.println(Produzione_Energia);      
  
     Serial.print(F("Potenza Consumata in Casa Kw: "));
     Serial.println(Consumo_Energia);   

    digitalWrite(2, HIGH);   // attivazione uscita D2 sempre high per controllo stato resistenza            
    Ventola = digitalRead(3);  //*INGRESSO digitale PER CONTROLLO WEB STATO VENTOLA
    caldaiaON = digitalRead(4);  //*INGRESSO digitale PER CONTROLLO WEB STATO CALDAIA 
    Resistenza = digitalRead(9);  //*INGRESSO digitale PER CONTROLLO WEB STATO resistenza
  
  Volt = analogRead(A0) * 0.5; // valore sensore aria in volt
  TempAria = Volt;   // temperatura aria in °C
  delayMicroseconds(120);  // 120 µs (min time reading = 100 µs x channel) 
  TempAria = TempAria+analogRead(A0) * 0.5;
  delayMicroseconds(120);  // 120 µs (min time reading = 100 µs x channel) 
  TempAria = (TempAria+analogRead(A0) * 0.5)/3;
  delayMicroseconds(120);  // 120 µs (min time reading = 100 µs x channel) 


  Volt = analogRead(A1) * 0.5;  // valore sensore acqua in volt
  TempAcquaOUTtermosolare = Volt; // temperatura acqua in °C +X°C PER COMPENSAZIONE TERMOMETRO TRIVALVOLA
  delayMicroseconds(120);   // 120 µs (min time reading = 100 µs x channel) 
  TempAcquaOUTtermosolare =  TempAcquaOUTtermosolare + (analogRead(A1) * 0.5);
  delayMicroseconds(120);   // 120 µs (min time reading = 100 µs x channel) 
  TempAcquaOUTtermosolare =  (((TempAcquaOUTtermosolare + (analogRead(A1) * 0.5))/3)+3); //calcolo media di 3 valori letti
  delayMicroseconds(120);   // 120 µs (min time reading = 100 µs x channel) 

  Volt = analogRead(A2) * 0.5;  // valore sensore acqua in volt
  TempAcquaINGtermosolare = Volt; // temperatura acqua in °C +X°C PER COMPENSAZIONE TERMOMETRO TRIVALVOLA
  delayMicroseconds(120);   // 120 µs (min time reading = 100 µs x channel) 
  TempAcquaINGtermosolare =  TempAcquaINGtermosolare + (analogRead(A2) * 0.5);
  delayMicroseconds(120);   // 120 µs (min time reading = 100 µs x channel) 
  TempAcquaINGtermosolare =  (((TempAcquaINGtermosolare + (analogRead(A2) * 0.5))/3)+3); //calcolo media di 3 valori letti
  delayMicroseconds(120);   // 120 µs (min time reading = 100 µs x channel)
  
  
  Serial.print("Temp. Acqua ING Termosolare: ");
  Serial.println(TempAcquaINGtermosolare);

  Serial.print(F("Temp. Acqua OUT Termosolare: "));
  Serial.println(TempAcquaOUTtermosolare, 1);
  otherSensorReadingCaldaia = caldaiaON;
  
  Serial.print(F("Temp. Aria Centrale Termica: "));
  Serial.println(TempAria, 1);
  otherSensorReadingAria = Ventola; 

  if (TempAria > (TempAriaMax + Isteresi)) {
    digitalWrite(7, HIGH);                                 // relay ventola ON
    digitalWrite(5, HIGH);                                 //*VENTILAZIONE ATTIVATA
    Serial.println("Aria >30°C - Ventola ON");
  }
  else if (TempAria < (TempAriaMax - Isteresi)) {
    digitalWrite(7, LOW);                                   // relay ventola OFF
    digitalWrite(5, LOW);                                    //*VENTILAZIONE DISATTIVATA
    Serial.println(F("Aria <30°C - Ventola OFF")); 
  }

  if ((TempAcquaOUTtermosolare > (TempAcquaMax + Isteresi)) && mela==1) (timer0_millis = 0, mela = 0 );
  if (TempAcquaOUTtermosolare > (TempAcquaMax + Isteresi) && (millis()>30000)) {

    digitalWrite(8, LOW);                                   // relay caldaia OFF
    digitalWrite(6, LOW);                               //*USCITA IN PARALLELO AL SEGNALE CALDAIA PER TELECONTROLLO
    Serial.println(F("Temp. Acqua Bollitore >43°C - Caldaia OFF"));
  }
    else if (TempAcquaOUTtermosolare < (TempAcquaMax - Isteresi)) {
     digitalWrite(8, HIGH);                                  // relay caldaia ON
     digitalWrite(6, HIGH);        //*USCITA IN PARALLELO AL SEGNALE CALDAIA PER TELECONTROLLO
     mela=1;
     Serial.println(F("Temp. Acqua Bollitore <43°C - Caldaia ON")); 
  }

  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println(F("disconnecting..."));
    client.stop();
  }

  // if you're not connected, and ten seconds have passed since
  // your last connection, then connect again and send data: 

  if (millis() < lastConnectionTime) lastConnectionTime = millis();    // evita il blocco dopo 50gg poiché millis() si azzera

  if (!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    DataString = "TempAria,";
    DataString += FloatFormat(TempAria, 10, 1, false, true);
    
    DataString += "\nVentola,";
    DataString += otherSensorReadingAria;  
    
    DataString += "\nResistenza,";
    DataString += Resistenza; 
    
    DataString += "\nTemp_Acqua_ING_termosolare,";
    DataString += FloatFormat(TempAcquaINGtermosolare, 10, 1, false, true); 
    
    DataString += "\nTemp_Acqua_OUT_termosolare,";
    DataString += FloatFormat(TempAcquaOUTtermosolare, 10, 1, false, true);
    
    DataString += "\nCaldaia,";
    DataString += otherSensorReadingCaldaia; 
    
    DataString += "\nConsumo_Energia,";
    DataString += FloatFormat(Consumo_Energia, 10, 1, false, true); 
    
    DataString += "\nProduzione_Energia,";
    DataString += FloatFormat(Produzione_Energia, 10, 1, false, true);
    
    sendData(DataString);
  }
  // store the state of the connection for next time through
  // the loop:
  lastConnected = client.connected();
}

// this method makes a HTTP connection to the server:

void sendData(String thisData) {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println(F("connecting..."));
    // send the HTTP PUT request:
    client.print("PUT /v2/feeds/");
    client.print(FEEDID);
    client.println(".csv HTTP/1.1");
    client.println("Host: api.cosm.com");
    client.print("X-ApiKey: ");
    client.println(APIKEY);
    client.print("User-Agent: ");
    client.println(USERAGENT);
    client.print("Content-Length: ");
    client.println(thisData.length());

    // last pieces of the HTTP PUT request:
    client.println("Content-Type: text/csv");
    client.println("Connection: close");
    client.println();

    // here's the actual content of the PUT request:
    client.println(thisData);
    Serial.println(thisData);
  } 
  else {
    // if you couldn't make a connection:
    Serial.println(F("connection failed"));
    Serial.println();
    Serial.println(F("disconnecting..."));
    client.stop();
  }
  // note the time that the connection was made or attempted:
  lastConnectionTime = millis();
}

String FloatFormat(float X, char Size, unsigned char Decimal, boolean Plus, boolean AutoReduce) {
  char Buffer[Size + 1];
  String Z = dtostrf(X, Size, Decimal, Buffer);
  if (Plus && X > 0) Z[Z.lastIndexOf(' ')] = '+';
  if (AutoReduce) Z.trim();
  return Z;
}

Secondo me dovresti andare ad eliminazione:

  • se resetti solo arduino si ripristina?
  • se resetti solo il router?
  • inserire dei serial.print e verificare in quale punto si pianta, lasciando un pc con monitor seriale aperto

io ad esempio con uno sketch simile mi sono accorto che la funzione += per concatenare le stringhe aveva un bug!

Una volta che isoli il problema diventa più facile risolverlo, il fatto che "non funzioni" dopo 3gg non aiuta a trovare la causa!

Ciao!

tapirinho:
io ad esempio con uno sketch simile mi sono accorto che la funzione += per concatenare le stringhe aveva un bug!

E' noto: Arduino: Crashes and errors when concatenating Strings - Stack Overflow
C'era un bug risolto dall'IDE 1.0.3 o forse prima, non ricordo.

Ma usare la classe String object (e non le stringhe, ovvero vettori/array di caratteri) può portare all'esaurimento della memoria in quanto ogni volta che concateni String object il micro deve riallocare la memoria. Ma può capitare che riallocando, la memoria si deframmenti rendendo alcune celle non più allocabili. Un pò quello che capita con i file sull'hard disk con Windows. Ma li di spazio ne hai molto e poi ogni tanto usi Defrag.
La riprova la puoi fare usando la libreria freeRam che ti dice quanta ram libera c'e' (durante il loop non basta nella setup) :

Sarebbe meglio non usare le String ma le stringhe C-style:

tempo fa mi era capitata una cosa simile:

fino all' IDE 1.0.3 lo sketch qui sotto si bloccava
http://forum.arduino.cc/index.php?topic=151106.30

ora dall'IDE 1.0.4 in poi non si pianta più, in ogni caso non ho più utilizzato quel metodo per creare le stringhe!

aiaiaiaiiii, mi sembra di capire che devo riscrivere il codice...

Normalmente quando si blocca arduino, basta spegnerlo e riaccenderlo che tutto riparte, ma a volte, se non resetto anche il router, xiveli non si "riprende" i dati aggiornati...

La base dello sketch era quella pubblicata su cosm e non ho fatto altro che aggiungere un po' di sensori...

Come primo passo proverò a lasciare il pc collegato ad arduino, vediamo che succede, non credo d'essere in grado di modificare le string, non saprei da dove iniziare...
Grazie

Si potrebbe fare. Prima di tutto le modifiche riguardano ovunque usi la variabile DataString.
La prima cosa è capire quanto occupa al massimo il testo dentro questa variabile.
Nel programma ci sono una valanga di scritte che vengono aggiunte a DataString

...
    DataString += "\nVentola,";
    DataString += otherSensorReadingAria;  
    DataString += "\nResistenza,";
...

Saputo questo allora dovrai riscrivere la dichiarazione di DataString come:

byte DataString[201];

Io ho ipotizzato 200 caratteri +1 di fine stringa (carattere '\0')

Poi si può usare la snprintf() per stampare tutte quelle frasi dentro alla stringa:
http://www.cplusplus.com/reference/cstdio/snprintf/
Qualcosa del genere al posto dei vari DataString= e += qualcosa:

int TAi=(int)TempAria;   // parte intera penso basti da 0 a +32000
int TAd=((int)(TempAria*10)%10);  // parte decimale, 1 decimale
snprintf ( DataString , 201, "TempAria, %d.%d\nVentola,\nResistenza,%d",TAi,TAd,otherSensorReadingAria,Resistenza);

Il problema sono i float che devono essere stampati la parte intera e la parte decimale separatamente (la funzione accetterebbe anche %f per i float, ma non su Arduino)

Poi c'e' la sendData che come parametro sarebbe:

void sendData(byte thisData[]) {
...
client.println(strlen(thisData));    // invece di .length

Non va più niente...
o meglio, Arduino funziona bene, nel senso che continua a controllare l'accensione e lo spegnimento della caldaia e della ventola di aspirazione, ma i dati su xively non vengono più aggiornati... nemmeno dopo spegnimento e riavvio del ruoter e di Arduino...
Avrò devastato la memoria interna?
Devo provar cambiando Arduino...
Mi dovrò armare di pazienza e rifare tutto :frowning:

La memoria non si distrugge da sé, nel senso che non la puoi rovinare con un programma.
Più probabile che tu la saturi. Se dici di generare un sacco di stringhe, è molto più probabile che tu abbia saturato la SRAM. E creare dei buffer così grandi non fa altro che accelerare la presentazione del problema.

Ho notato che ricaricando lo sketch su arduino spesso mi appare un messaggio di errore, a volte devo ripetere l'operazione anche 20 volte... dipende sempre dalla SRAM satura?

Ma se la ram si saturasse, non dovrebbe smettere di far funzionare anche gli altri controlli ? Elvis dice che la scheda continua a gestire caldaia/ventole...

elvis:
Ho notato che ricaricando lo sketch su arduino spesso mi appare un messaggio di errore, a volte devo ripetere l'operazione anche 20 volte... dipende sempre dalla SRAM satura?

Questo non è un errore di SRAM satura. La SRAM la satura il programma in esecuzione, ma mentre carichi uno sketch questo non è in esecuzione. Che tipo di errore ricevi, scusa? Non è che hai qualcosa sui pin D0 e D1 che ti possono dare noia durante la programmazione?

D0 e D1 sono scollegati.

In questi giorni sono via per lavoro, appena rientro ti dico il messaggio di errore che mi appare.

Provando a caricare lo sketch in questione su un arduino UNO che ho con me mi è apparso il messaggio: "avrdude: stk500_getsynk(): not in sinc resp=0xff"

non ricordo se sia lo stesso errore, ci assomiglia comunque... ma che significa?

Stai caricando lo sketch dall'IDE di Arduino su una Arduino UNO?
Sulla scheda c'è qualche shield montato?

Positivo, carico lo sketch su arduino UNO senza nessun shield montato.

Molto interessante!
Giovedì, al mio rientro a casa provo.
Grazie per la dritta.

Ciao pablos, scusa del ritardo...
C'è un problema... io il pin 4 lo uso come input...
Mannaggia...
Ho liberi solo 0 e 1...

Bene, ho rifatto la scheda.
Ho seguito i tuoi consigli ed ora il pin 4 è libero ed utilizzo al suo posto il pin 1.
Funziona alla grande!
Son ben 5 giorni che funziona senza bloccarsi.

Grazie pablos!

Il problema della classe String è ormai noto e, come ti hanno scritto in precedenza, la concatenazione delle stringhe porta nel tempo ad una saturazione delle memoria SRAM.

Ci sono due soluzioni al tuo problema:
1 - dichiarare l'oggetto DataString solo a livello locale creando una routine di invio dati.
2 - lasciare la dichiarazione globale , ma inizializzare non con una stringa vuota ma con una stringa la cui lunghezza sia la massima possibile.

La prima soluzione funziona perché l'oggetto String viene creato al partire della routine e distrutto alla sua uscita, liberando la memoria allocata.
La seconda soluzione funziona perchè solo concatenazioni più lunghe di quella iniziale creano il problema.

In qualsiasi caso, ti consiglio di ridurre il più possibile la lunghezza delle costanti stinga da concatenare (ad esempio "Temp_Acqua_ING_termosolare" riducilo in "TempIngH2O")