1

i made a weather station which is build on a ATmega2560 mini pro, Esp8266 module which communicate with atmega on serial1 which sends values to thingspeak, an TSL2561, 2.4 tft lcd, BMP180, DHT22 and a dust sensor module PMS5003 which is set on serial3 on mega2560. I made the wiring, program etc. the weather station is working fine for some days when it freezes. The problem is that thingspeak reports that it receive some data every 6 mins like i set it but the data received is blank. Not 0, or any other value, just blank data. I'm thinking it could be a problem with SRAM since it loses the values it reads. But why the loop is still working since it sends blank data to thingspeak ?

Atmega reads all values from sensors, then communicates with esp8266 by serial and using AT commands it sends the values read to thingspeak. So in my opinion it reads the values, but it won't stores them, then it sending blank data to thingspeak. If i reset the arduino it works fine for some days when suddenly it decides to stop working.

After compiling the program the arduino ide is reporting this:

Sketch uses 28,890 bytes (11%) of program storage space. Maximum is 253,952 bytes. Global variables use 1,800 bytes (21%) of dynamic memory, leaving 6,392 bytes for local variables. Maximum is 8,192 bytes.

So, my program it's not filling the SRAM. I'm a beginner in C++ so i tried to do my best with programming.

Link to thingspeak weather station: https://thingspeak.com/channels/116912

The code:

#include <SFE_BMP180.h>
#include <Wire.h>
#include <DHT.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include "SWTFT.h" // Hardware-specific library

#define DHTPIN 25     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)
#define ALTITUDE 320.0 // Altitude in Grasse


// Assign human-readable names to some common 16-bit color values:
#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

SWTFT tft;

DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino
SFE_BMP180 pressure;

Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);

//double bmptemp; //temp bmp rectificata cu 1.9 grade -
float hum;  //Stores humidity value
float temp; //Stores temperature value
float lux; //Stores lux luminosity
char status; //used by bmp180
double T,P,p0; //p0 - sea-level compensated pressure in mb, T - temperature, P = absolute pressure in mb


#define IP "184.106.153.149" // thingspeak.com IP address; see their website for more detail
String GET = "GET /update?key=NWHWO6SLWNJP3HGQ"; // you channel will have unique code
int concentration=0;

//cod dust sensor
#define LENG 31   //0x42 + 31 bytes equal to 32 bytes
unsigned char buf[LENG];

int PM01Value=0;          //define PM1.0 value of the air detector module
int PM2_5Value=0;         //define PM2.5 value of the air detector module
int PM10Value=0;         //define PM10 value of the air detector module



void setup() {

  pinMode(17, OUTPUT); //pin pt esp - on /off
  pinMode(16, OUTPUT); //pin buzzer
  pinMode(31, OUTPUT); //pin on/off dust sensor

  Serial.begin(9600); // this is to start serial monitoring with your Arduino IDE Serial monitor.
  Serial1.begin(9600); // this is to start serial communication with the ESP via Software Serial.
  Serial3.begin(9600); //serial dust sensor



  Serial.println("Begin");
  tft.reset();
  uint16_t identifier = tft.readID();
  tft.begin(identifier);


  dht.begin();

  if (!pressure.begin()) {
    Serial.println("BMP180 init fail"); // Oops, something went wrong, this is usually a connection problem,
    while(1); // Pause forever.
    }

  if(!tsl.begin()) {
    /* There was a problem detecting the ADXL345 ... check your connections */
    Serial.print("Ooops, no TSL2561 detected ... Check your wiring or I2C ADDR!");
    while(1);
  }
  //tsl.setGain(TSL2561_GAIN_1X);      /* No gain ... use in bright light to avoid sensor saturation */
  //tsl.setGain(TSL2561_GAIN_16X);     /* 16x gain ... use in low light to boost sensitivity */
  tsl.enableAutoRange(true);            /* Auto-gain ... switches automatically between 1x and 16x */
  tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);  /* 16-bit data but slowest conversions */

}


void loop() {
  digitalWrite(31, LOW);
  digitalWrite(17, LOW);
  Serial.println("-----------------------");
  dht22 ();
  bmp120 ();
  tsl2561();
  dust();
  Serial.println("-----------------------");


  tft.fillScreen(BLACK);
  tft.setRotation(1);
  tft.setCursor(0, 0);

  tft.setTextColor(GREEN);    
  tft.setTextSize(2);
  tft.println("DHT22");
  tft.setTextColor(WHITE);    
  tft.setTextSize(2);
  tft.print("Temperature = ");
  tft.print(temp);
  tft.println(" C");
  tft.print("Humidite = ");
  tft.print(hum);
  tft.println(" %");
  tft.println();

  tft.setTextColor(GREEN);    
  tft.setTextSize(2);
  tft.println("BMP180");
  tft.setTextColor(WHITE);    
  tft.setTextSize(2);
  tft.print("Temperature = ");
  tft.print(T);
  tft.println(" C");
  tft.print("Pression = ");
  tft.print(p0);
  tft.println(" mb");
  tft.println();

  tft.setTextColor(GREEN);    
  tft.setTextSize(2);
  tft.println("TSL2561");
  tft.setTextColor(WHITE);    
  tft.setTextSize(2);
  tft.print("Luminosite = ");
  tft.print(lux);
  tft.println(" Lux");
  tft.println();


  tft.setTextColor(GREEN);    
  tft.setTextSize(2);
  tft.println("Pollution aux particules");
  tft.setTextColor(WHITE);    
  tft.setTextSize(2);
  //tft.println("Concentration - ug/m3");
  tft.print("PM1.0: ");
  tft.print(PM01Value);
  tft.println(" ug/m3");
  tft.print("PM2.5: ");
  tft.print(PM2_5Value);
  tft.println(" ug/m3");
  tft.print("PM10: ");
  tft.print(PM10Value);
  tft.println(" ug/m3");
  //tft.println("Pcs/0.01cf");  




  String tempdht22 = String(temp);// turn integer to string
  String humdht22 = String(hum);
  String tempbmp180 = String(T);
  String pressbmp180 = String(p0);
  String lum = String(lux);
  String pol01 = String(PM01Value);
  String pol25 = String(PM2_5Value);
  String pol10 = String(PM10Value);
  esp8266(tempdht22, humdht22, tempbmp180, pressbmp180, lum, pol01, pol25, pol10);
  Serial.println("Waiting..");
  delay(300000);




}

void dht22 () {
//Read data and store it to variables hum and temp
    hum = dht.readHumidity();
    temp= dht.readTemperature();
    //Print temp and humidity values to serial monitor
    Serial.print("Humidity: ");
    Serial.print(hum);
    Serial.println(" % ");
    Serial.print("Temp: ");
    Serial.print(temp);
    Serial.println(" C"); 
}

//cod pt dust sensor 
void dust () {
  digitalWrite(31, HIGH);
  Serial.println("High Pms5003");
  delay(5000);
  for (int i=0; i <= 60; i++){
  if(Serial3.find(0x42)){    //start to read when detect 0x42
    Serial3.readBytes(buf,LENG);

    if(buf[0] == 0x4d){
      if(checkValue(buf,LENG)){
        PM01Value=transmitPM01(buf); //count PM1.0 value of the air detector module
        PM2_5Value=transmitPM2_5(buf);//count PM2.5 value of the air detector module
        PM10Value=transmitPM10(buf); //count PM10 value of the air detector module 
      }           
    } 
  }

  Serial.print("PM1.0: ");  
  Serial.print(PM01Value);
  Serial.println("  ug/m3");            

  Serial.print("PM2.5: ");  
  Serial.print(PM2_5Value);
  Serial.println("  ug/m3");     

  Serial.print("PM10: ");  
  Serial.print(PM10Value);
  Serial.println("  ug/m3");   
  Serial.println();
  delay(1000);
  }
  delay(1000);
  Serial.println("Low Pms5003");
  digitalWrite(31, LOW);
}

char checkValue(unsigned char *thebuf, char leng)
{  
  char receiveflag=0;
  int receiveSum=0;

  for(int i=0; i<(leng-2); i++){
  receiveSum=receiveSum+thebuf[i];
  }
  receiveSum=receiveSum + 0x42;

  if(receiveSum == ((thebuf[leng-2]<<8)+thebuf[leng-1]))  //check the serial data 
  {
    receiveSum = 0;
    receiveflag = 1;
  }
  return receiveflag;
}

int transmitPM01(unsigned char *thebuf)
{
  int PM01Val;
  PM01Val=((thebuf[3]<<8) + thebuf[4]); //count PM1.0 value of the air detector module
  return PM01Val;
}

//transmit PM Value to PC
int transmitPM2_5(unsigned char *thebuf)
{
  int PM2_5Val;
  PM2_5Val=((thebuf[5]<<8) + thebuf[6]);//count PM2.5 value of the air detector module
  return PM2_5Val;
  }

//transmit PM Value to PC
int transmitPM10(unsigned char *thebuf)
{
  int PM10Val;
  PM10Val=((thebuf[7]<<8) + thebuf[8]); //count PM10 value of the air detector module  
  return PM10Val;
} //cod dust sensor

void bmp120 () {
  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // Print out the measurement:
      Serial.print("Temp2: ");
      Serial.print(T);
      Serial.println(" C ");


      // Start a pressure measurement:
      // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
      // If request is successful, the number of ms to wait is returned.
      // If request is unsuccessful, 0 is returned.

      status = pressure.startPressure(3);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);

        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable P.
        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = pressure.getPressure(P,T);
        if (status != 0)
        {

          // The pressure sensor returns abolute pressure, which varies with altitude.
          // To remove the effects of altitude, use the sealevel function and your current altitude.
          // This number is commonly used in weather reports.
          // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
          // Result: p0 = sea-level compensated pressure in mb

          p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO)
          Serial.print("Pressure: ");
          Serial.print(p0);
          Serial.println(" mb");
        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");
}

void tsl2561 () {
  /* Get a new sensor event */ 
  sensors_event_t event;
  tsl.getEvent(&event);

  /* Display the results (light is measured in lux) */
  if (event.light)
  {
    Serial.print(event.light); Serial.println(" lux"); lux = event.light;
  }
  else
  {
    /* If event.light = 0 lux the sensor is probably saturated
       and no reliable data could be generated! */
    Serial.println("0 lux");
  }
}



void esp8266( String temp1, String humm, String temp2, String pression, String luminosite, String pol001, String pol025, String pol010) {
  //update value on thingspeak
  digitalWrite(17, HIGH);
  Serial.println("High ESP8266");
  delay(4000);
  Serial1.println("AT+RST"); // this resets the ESP8266.
  Serial.println("AT+RST"); // this is just echoing the command to your serial monitor so you can follow what is going on
  delay(2000);
  Serial1.println("AT");
  Serial.println("AT");
  delay(5000);
  if(Serial1.find("OK")){
      Serial.println("OK");
      Serial.println("Connected");
  }   

  Serial.println("in the update loop"); 
  //ESP8266.println("AT+RST"); // it seems that mine works better if I reset it everytime before I do CIPSTART
  //Serial.println("AT+RST");
  //delay(5000);
  String cmd = "AT+CIPSTART=\"TCP\",\""; //standard code. see https://github.com/espressif/esp8266_at/wiki //
  cmd += IP; // += is concatenating the previous cmd string with the content of IP
  cmd += "\",80"; // same thing here it just keep adding stuff to the cmd string content
  Serial1.println(cmd);//type in the string in cmd into the ESP8266
  Serial.println(cmd);
  delay(1000);

  if(Serial1.find("Error")){
    Serial.println("AT+CIPSTART Error");
    digitalWrite(16, HIGH);   
    delay(250);              
    digitalWrite(16, LOW);   
    return;
  }
  cmd = GET + "&field1=" + temp1 + "&field2=" + humm + "&field3=" + temp2 + "&field4=" + pression + "&field5=" + luminosite + "&field6=" + pol001 + "&field7=" + pol025 + "&field8=" + pol010 + "\r\n\r\n";
  Serial1.print("AT+CIPSEND="); 
  Serial1.println(cmd.length());
  Serial.print("AT+CIPSEND=");
  Serial.println(cmd.length());
  delay(1000);
  if(Serial1.find(">")){ // if ESP8266 return the > prompt back from the CIPSEND command, you are set, if not something is wrong
    Serial1.print(cmd); //type in the GET command string and done
    Serial.print(">");
    Serial.println(cmd);
    Serial.println("OK Sent");    
  }
  else
  {
   Serial.println("AT+CIPSEND error");
    digitalWrite(16, HIGH);   
    delay(250);              
    digitalWrite(16, LOW);    
  }
  delay(1000);
  digitalWrite(17, LOW);
  Serial.println("Low ESP8266");
}

Here i uploaded the data file from thingspeak. You can see that until 2016-06-17 14:58:00 UTC it was working fine then thingspeak started receiving blank data. It received something but only blank data. The weather station is in another location so i don't have acces all time to reset it. http://www.filedropper.com/feeds8

[Shown below are some lines from the front, the transition point, and the end of the feeds (8).csv file at Andrei's filedropper link. – jw]

created_at,entry_id,field1,field2,field3,field4,field5,field6,field7,field8
2016-06-16 05:50:45 UTC,1,19.10,92.70,20.80,1003.02,1512.00,8,15,15
2016-06-16 05:55:07 UTC,2,19.00,94.00,20.91,1003.09,1659.00,41,54,61
2016-06-16 06:01:32 UTC,3,19.10,92.70,20.98,1003.11,2233.00,6,7,12
2016-06-16 06:07:57 UTC,4,19.00,92.90,21.16,1003.11,2620.00,6,7,11
2016-06-16 06:14:22 UTC,5,19.10,92.70,21.19,1002.97,2701.00,6,6,12
2016-06-16 06:20:48 UTC,6,19.10,92.20,21.44,1002.97,2973.00,220,291,327
2016-06-16 06:27:13 UTC,7,19.30,92.20,21.47,1002.99,3197.00,5,6,7
...
2016-06-17 14:19:30 UTC,305,22.70,50.50,23.43,1013.88,1956.00,1,1,1
2016-06-17 14:25:55 UTC,306,22.60,51.20,23.27,1013.88,1979.00,1,1,1
2016-06-17 14:32:20 UTC,307,22.70,50.10,23.18,1014.00,1962.00,1,1,1
2016-06-17 14:38:45 UTC,308,22.70,49.50,23.17,1014.03,1967.00,1,1,1
2016-06-17 14:45:10 UTC,309,22.50,50.90,23.55,1014.01,1856.00,2,2,2
2016-06-17 14:51:35 UTC,310,22.60,51.80,23.62,1013.99,1870.00,1,1,1
2016-06-17 14:58:00 UTC,311,22.60,50.80,23.21,1013.94,1987.00,1,2,2
2016-06-17 15:04:26 UTC,312,"",,,,,,,
2016-06-17 15:10:51 UTC,313,"",,,,,,,
2016-06-17 15:17:16 UTC,314,"",,,,,,,
2016-06-17 15:23:41 UTC,315,"",,,,,,,
2016-06-17 15:30:06 UTC,316,"",,,,,,,
2016-06-17 15:36:31 UTC,317,"",,,,,,,
2016-06-17 15:42:56 UTC,318,"",,,,,,,
...
2016-06-17 22:59:18 UTC,386,"",,,,,,,
2016-06-17 23:05:43 UTC,387,"",,,,,,,
2016-06-17 23:12:08 UTC,388,"",,,,,,,
2016-06-17 23:18:33 UTC,389,"",,,,,,,
2016-06-17 23:24:58 UTC,390,"",,,,,,,
2016-06-17 23:31:23 UTC,391,"",,,,,,,
2016-06-17 23:37:48 UTC,392,"",,,,,,,
2016-06-17 23:44:13 UTC,393,"",,,,,,,

I went and saw the station, it's more like an electrical problem imo because if i reset arduino nothing happens. The data readed by arduino on dht22 is nan and the rest of the sensors is working fine. The only way i could make dht22 reading again is to unplug the power and plug it back. So that's why i think it's more an electrical problem but can't figure why dht22 stops responding and need to switch off all power to bring it back to life. I will try putting an capacitor on wires to dht22 to see if it's better.

2
  • Please edit your question and add examples of output from when it is working, and from when it isn't. Your statement that “the data received is blank” is ambiguous. Do you mean the whole transmission, or just the data fields; and by blank, do you mean "not there" or "blank characters"? To avoid that ambiguity, please edit your question and add examples of output from when it is working, and from when it isn't. Commented Jun 17, 2016 at 23:46
  • I edited some of those lines into the question. The link to filedropper seems cumbersome to use. ¶ What I'd like to see, instead of data as processed by thingspeak, is what was sent to thingspeak. Ie, what the Arduino is sending, not what thingspeak extracted from that input. I imagine field names are missing (in the http GET request) as well as data Commented Jun 18, 2016 at 3:39

1 Answer 1

1

You may have a power problem, but with all those libraries, I would also suspect memory issues with String. The percentages reported by the IDE do not show actual String memory usage, just the declared variables and double-quoted string constants, like "BMP180 init fail".

I think those humidity sensors have a heating cycle, so maybe they're causing a power sag, or maybe the sketch has run amok and is constantly requesting conversions.

Regardless, instead of building a String to be printed all at once, just print the pieces. That is, instead of this:

String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += IP;
  cmd += "\",80";
  Serial1.println(cmd);

...do this:

Serial1.println( F("AT+CIPSTART=\"TCP\",\"") );
Serial1.print( IP );
Serial1.print( F("\",80") );

This saves copying bytes into buffers, reallocating Strings, copying them to the output buffer... yuck.

The F("x bytes") macro also saves x bytes of RAM each time you use it on a double-quoted string constant!

And this:

cmd = GET + "&field1=" + temp1 + "&field2=" + humm + "&field3=" + temp2 + "&field4=" + pression + "&field5=" + luminosite + "&field6=" + pol001 + "&field7=" + pol025 + "&field8=" + pol010 + "\r\n\r\n";

OMG. Use separate Serial1.print statements and F() macros. However, because you have to send the command length first to the ESP8266, don't pass them in as Strings, pass them as ints or floats, and add up the individual string lengths.

There are several ways to do this, depending on the old RAM-vs-speed tradeoff. Here's a minimal RAM approach:

  //  Pass in values, not Strings
  esp8266( temp, hum, T, p0, lux, PM01Value, PM2_5Value, PM10Value );
}
    ...

void esp8266( float temp1, float humm, float temp2, float pression, float luminosite, int pol001, int pol025, int pol010 )
{
    ...

  //  Start with the fixed-length string constants:
  //     GET + 8 * "&field#" + line termination
  size_t cmdLength = strlen(GET) + 8 * 8 + 4;

  //  Convert each value to a char array to see how big each one is...
  char buf[16]; // to hold temporary "char strings"

  unsigned char decimalPlaces = 2;
  dtostrf( temp1, (decimalPlaces + 2), decimalPlaces, buf);
  cmdLength += strlen(buf);

  dtostrf( humm, (decimalPlaces + 2), decimalPlaces, buf);
  cmdLength += strlen(buf);

  dtostrf( temp2, (decimalPlaces + 2), decimalPlaces, buf);
  cmdLength += strlen(buf);
     ...
  itoa( pol10, buf, 10 );  // value, char *, base
  cmdLength += strlen(buf);

  //  Now we know the total length
  Serial1.print("AT+CIPSEND="); 
  Serial1.println( cmdLength ); //  <-- calculated!
  delay(1000);

  if (Serial1.find(">")) {

    // send all the same pieces of the GET command
    Serial1.print( GET );

    Serial1.print( F("&field1=") );
    dtostrf( temp1, (decimalPlaces + 2), decimalPlaces, buf);
    Serial1.print( buf );

    Serial1.print( F("&field2=") );
    dtostrf( humm, (decimalPlaces + 2), decimalPlaces, buf);
    Serial1.print( buf );

    Serial1.print( F("&field3=") );
    dtostrf( temp2, (decimalPlaces + 2), decimalPlaces, buf);
    Serial1.print( buf );
        ...
    itoa( pol010, buf, 10 );  // value, char *, base
    Serial1.print( buf );

    Serial1.print( F("\r\n\r\n") );

NOTE: It is important that you use the same technique to calculate the length of one piece and to print that piece. Here, the same dtostrf call with the same decimalPlaces is used for each piece. Ditto for itoa.

The speed penalty is that you convert each parameter twice, but this is probably still quicker than all the alloc/realloc/delete/copy that String was doing.

The RAM advantage is that you are using only 16 bytes for buf instead of hundreds of bytes on the heap (that's where String actually stores its characters).

The program space advantage is about 1600 bytes for not using the String library.

I hope you now see that the apparent "convenience" of using the String class has real costs in speed, RAM and program size. String also affects the long-term stability of your program: you get weird crashes, hangs or string values.

2
  • Thank you very much for your reply. I am a beginner in C programming, i started learning C about some months ago, so i will try to understand what you told me about optimising the program and then applying to my project, because honestly now i don't understand them :) I did a research on google and saw that others are having problems with DHT22 sensor that stops working and need to replug it on power to works. When i saw the weather station today like i told all the sensors was running except the dht22 which replied as nan.Since nan is not an int value thingspeak is not accepting transmission
    – Andrei
    Commented Jun 18, 2016 at 20:39
  • The dht22 is doesn't have a heating time so i could attach the vcc pin of dht22 to an arduino pin and activate it when i need to read the temperature. The library is made like this when dht22 is not responding it give a value of nan. I could modify the library to give a value of 50 degrees for example but this is not a solution to my problem. If you have any other comments regarding my program feel free to help me :) Thank you !
    – Andrei
    Commented Jun 18, 2016 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.