Vaisala WXT520 weather sensor

I'm new to Arduino, and eager to learn but there is too many information regarding same problems and I'm simply lost.
I would like to make a RS232 to SD data logger but I'm stuck when it comes to dealing with serial communication.
I'm aware that it has already been discussed and there are good tutorials (even already built loggers) but I would like to make it from scratch and get into this amazing Arduino world.
I understand "Serial" and Serial monitor, and I've been practicing with it, but can't figure out the best way to solve the following:

  1. Send "0R0+CR+LF" via SoftwareSerial
  2. Capture the response from device via SoftwareSerial and display it on Serial monitor (in the code comments, you'll see how the response looks like).
    This is just a beginning, later I plan to write received string on SD card (just pass it as it is, without parsing it as it is already CSV).
    I've built a RS232 shifter and it is working when I connect Arduino to another PC running terminal application (I can chat using Serial monitor and PC2).
/*Arduino Uno logger for Vaisala WXT520 weather sensor*/

#include <SoftwareSerial.h>

SoftwareSerial vaisala(2, 3); // RX, TX

String command = "0R0"; //request data from sensor, must be followed with CR+LF
String data = ""; // maybe change this approach and not use String

void setup()  
{
  vaisala.begin(19200); // default device settings are 19200,8,N,1
}

void loop()
{  
  vaisala.println(command); //println because CR+LF must be sent

//device will return the following string:
//  0R0,Dx=005D,Sx=2.8M,Ta=23.0C,Ua=30.0P,Pa=1028.2H,Rc=0.00M,Rd=10s,Th=23.6C<cr><lf>
/* capture whole received string and print it to Serial Monitor */ 
 if (vaisala.available()>0)
    data = vaisala.read();
  
  Serial.println(data);
  delay(2000); //
}

Unfortunately, I can't test this sketch because I can't properly communicate with the mentioned device but that is another issue I'll try to solve myself (I think built in RS232 port on device is broken, so I'll try to use RS485 but I'm waiting RS485/232 converter to arrive).
Regarding the device response given in the code comment, what is the best approach to deal with it?
Thanks in advance!!!

but can't figure out the best way to solve the following:

  1. Send "0R0+CR+LF" via SoftwareSerial

What you are doing looks reasonable, except for using String.

char *command = "0R0"; //request data from sensor, must be followed with CR+LF
vaisala.println(command); //println because CR+LF must be sent

  1. Capture the response from device via SoftwareSerial and display it on Serial monitor (in the code comments, you'll see how the response looks like).

Do you need to send that command EVERY pass through loop? Every time you need to access data? Or once?

 if (vaisala.available()>0)
    data = vaisala.read();

You said that you understood Serial. This doesn't look like it. The Serial.read() function returns one character. Storing that one character as the only data in a String instance is silly. Appending it to the String instance might make sense, but storing the data in a char array (and adding a NULL after adding each character) would make more sense.

But, you need to understand when to stop reading/storing data for one record and when to start reading/storing for the next record.

Thanks for fast response!

  1. I will take a look what is a difference using char and pointer (*), thanks for advice.
  2. Yes, I need to send "request command" every time when I want to receive data, so I think it's OK to do it in a loop()

About my understanding of Serial: I was trying to explain that I know how to use Serial monitor and basic operations (read/write), I don't have a good knowledge regarding Serial class :blush:

I think that each response from device is finished with CR+LF (but I'll confirm this when my RS485 converter arrives), so I'll try to take that to stop reading the "vaisala" port. The biggest problem for me is to understand how to construct "char array" and check for "CR+LF". As I said, I've followed a couple of tutorials regarding this, but still can't get it into my head.

Thanks for all the help!

This code will read, and store all the serial data between start and end of packet markers:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

You can remove all the SOP stuff, since you don't have a start-of-packet marker. Set started to true when you send the 0R0 command.

Where it says "The end of packet marker arrived. Process the packet", you can store the data in inData to the SD card. Make sure that inData is sized appropriately for your amount of data, and that the limit values are adjusted appropriately.

PaulS, thank you for the example code!
I'm starting to get the logic for populating char array, but still can't resolve a couple of things.

  1. I'm assuming that every response from device has CR+LF so I should use that information to finish reading the serial buffer, but I don't know the proper way to translate this into code.
    In your example you're defining '>' for EOP. What should I use instead of > to detect CR?
    a) '\0'
    b) 13
    c) something else

  2. Why are you defining a BYTE for index?
    I can understand the counter approach but I've always used an INT for this, so I'm confused.

  3. Can you please explain the use of '\0'? I know that it is treated as byte an it is used for ending a string.

Thanks for your effort to help me!

What should I use instead of > to detect CR?

'\n'

  1. Why are you defining a BYTE for index?

It can hold 255 different values. More than enough to walk an 80 element array. If you array is larger than that, use an int type variable for the index.

  1. Can you please explain the use of '\0'? I know that it is treated as byte an it is used for ending a string.

It is a NULL. A string is a NULL terminated array of chars. inData is an array of chars. It needs to be NULL terminated to qualify as a string, so that it can be passed to functions that expect a string.

1,2 and 3 perfectly CLEAR, thanks Paul!
I'll try to create a test sketch to verify all you mentioned.
Since I can't try it on actual Vaisala sensor, I'll use a terminal on another PC and route typed text to Serial monitor.
If everything is OK with a sketch, I shouldn't see any data in serial monitor until I hit ENTER on PC2.

Finally, I have my weather sensor operational. I can send and receive the data using terminal programs.
Unfortunately, my sketch is not working as I would like. I can send a "command" to Vaisala, but the response is not received properly.
I'm sure that Vaisala is sending the requested data because I have a separate "service connection" active and there is a "Vaisala monitor utility" where I can see all serial messages received and sent by Vaisala device.
I've tried to make some kind of debugging with LCD and Serial monitor, but got lost in the code, so I removed all these attempts.
Here is my sketch, so any suggestions are more than welcome:

#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"
#include <SD.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>

/* vaisala stuff */
#define EOD '\n' // EOD - end of data marker
boolean ended = false; // using for condition
char *command = "0XU"; //string to request data from sensor
char inData[128]; // char array for storing received bytes
byte index; // byte type is enough for storing received string
SoftwareSerial vaisala(2, 3); // RX, TX
RTC_DS1307 RTC;
char filename[] = "00000000.TXT"; 
const int chipSelect = 4;      // CS for SD card
LiquidCrystal lcd(14,15,5,6,7,8); // RS,EN,D4,D5,D6,D7
 
void setup()
{
  pinMode(14, OUTPUT); // RS for LCD, Ethernet Shield present, there's not enough digital pins
  pinMode(15, OUTPUT); // EN for LCD, Ethernet Shield present, there's not enough digital pins
  lcd.begin(16,2);
  Serial.begin(19200);
  Wire.begin();
  vaisala.begin(19200);
  lcd.print(" Vaisala WXT520 ");
  lcd.setCursor(0,1);
  lcd.print(" data logger v1 ");
  delay(3000);
  if (! RTC.isrunning()) {
    lcd.clear();
    lcd.print("RTC not OK");
    Serial.println("RTC is NOT running!");
    //RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  delay(100);
  Serial.print("Initializing SD card...");
  lcd.clear();
  lcd.print("SD card init...");
  delay(1000); // to be able to see the message
  
  pinMode(10, OUTPUT);
 
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    lcd.clear();
    lcd.print("SD error !!!");
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");
  lcd.clear();
  lcd.print("SD card OK!");
  delay(1000); // to be able to see the message
  lcd.clear();
  lcd.print(" Receiving data ");
  
}
 
void loop()
{
  vaisala.println(command); //println because CR+LF must be sent
  // Read all serial data available, as fast as possible
    
  while(vaisala.available() > 0) // this should become FALSE when there is no more new bytes - it will be -1
  {
    delay(200); // let the buffer fill up
    char inChar = vaisala.read(); // every byte from buffer will be compared to EOD
    if(inChar == EOD) // if EOD is detected, set 'ended' to TRUE and get out of while loop (jump to packet processing section)
    {
       ended = true;
       break; // exit WHILE loop
    }
    else
    {
    if(index < 127) // EOD not detected so loop further through indexes
      {
        inData[index] = inChar;
        index++;
        // if following line is uncomented, I get one empty line after each line of data !!!
        //inData[index] = '\0'; // terminate with a NULL so that char array can qualify as string
      }
    }
  }
  
  if(ended) //EOD marker detected, process data
  {
      DateTime now = RTC.now();                              // get time from RTC  
      getFilename(filename); // call method that constructs the file name using "date" data
      File dataFile = SD.open(filename, FILE_WRITE);
 
        // if the file is available, write to it:
        if (dataFile)
        {
          // time stamp from RTC
          dataFile.print(now.day(), DEC);
          dataFile.print('/');
          dataFile.print(now.month(), DEC);
          dataFile.print('/');
          dataFile.print(now.year(), DEC);
          dataFile.print(" , ");
          dataFile.print(now.hour(), DEC);
          dataFile.print(':');
          dataFile.print(now.minute(), DEC);
          dataFile.print(" , ");
          dataFile.println(inData);
          dataFile.close();
          Serial.println(inData); // attach received data
        }
         // if the file isn't open, pop up an error:
        else
        {
          Serial.print("error opening ");
          Serial.println(filename);
        }
     // Reset for the next packet
    ended = false;
    index = 0;
    //inData[index] = '\0';
  }
     delay(5000); // how often to query for new data from serial device
}

// method for constructing the file name
void getFilename(char *filename) {
  DateTime now = RTC.now(); 
  int year = now.year(); 
  int month = now.month(); 
  int day = now.day();
  filename[0] = '2';
  filename[1] = '0';
  filename[2] = (year-2000)/10 + '0';
  filename[3] = year%10 + '0';
  filename[4] = month/10 + '0';
  filename[5] = month%10 + '0';
  filename[6] = day/10 + '0';
  filename[7] = day%10 + '0';
  filename[8] = '.';
  filename[9] = 'T';
  filename[10] = 'X';
  filename[11] = 'T';
  return;
}

Either I'm not detecting end of line marker (which is CR+LF), or there is some other error.
LCD is showing "Receiving data" message, but in Serial monitor I can't see received data, and SD card is empty (the file havent been created at all because no data is processed).

Thanks in advance!

    delay(200); // let the buffer fill up

This is silly. You know what marks the end of a message. Read and store data, as fast as possible as the data arrives. It will not all arrive in one pass through loop(), no matter how little data there is, and how fast the serial baud rate is, unless you use a very large delay.

  vaisala.println(command); //println because CR+LF must be sent

Sending the command on EVERY pass through loop() doesn't make sense. How often do you really need to do this?

        // if following line is uncomented, I get one empty line after each line of data !!!

Because the device is sending a carriage return and a line feed. The "empty line" is the line feed. You need to ignore both CR and LF, NOT skip the needed NULL termination.

    //inData[index] = '\0';

This needs to be uncommented.

  filename[0] = '2';
  filename[1] = '0';
  filename[2] = (year-2000)/10 + '0';
  filename[3] = year%10 + '0';
  filename[4] = month/10 + '0';
  filename[5] = month%10 + '0';
  filename[6] = day/10 + '0';
  filename[7] = day%10 + '0';
  filename[8] = '.';
  filename[9] = 'T';
  filename[10] = 'X';
  filename[11] = 'T';

Or use sprintf()...

  1. Baud rate is "19200" and I know that END marker should be CR+LF. I've used '\n' but I don't think it's detected properly. My code is working when I'm using another PC, if I type a couple of characters and hit 'enter', Arduino receives it OK and all looks well (even if I comment '\0' line). So, I'm thinking that Vaisala device "can't hit 'enter' " or I don't know how to capture it, or how to mach the end of data.
    When I did some testing using PC2 and opened a file from SD card (using Notepad++) I can see that every line that was received by Arduino is ended with CR+LF, so '\n' should be OK for 'end of data marker', but I can't figure out why it's not working when Vaisala is attached :frowning:

  2. I need to send "0XR" command every time when I want new data from Vaisala. So, whenever I read one set of data, I need to send new request (pool the data) in order to receive new set of data. My idea is to set the delay at the end of loop(). If I want to query for data every 10 seconds, delay would be (10000). If there is some other solution I'll be glad to try it.

  3. about sprintf() - will take a look and try to understand why it is better (this part in my code, and almost everything else, is copied from existing examples).
    I'll do my best to make some progress, thanks a lot for all the comments and suggestions PaulS !!!

I've managed to receive the data from sensor, but only by using 'for' loop. I did the same for reading and printing the buffer. This only works if length of data is smaller than 63 bytes, if length is larger (in my case, each received message is between 150 and 170 bytes long, depending on measured values), everything falls apart :frowning:
I can customize the content of message in order to make it shorter, but it would be shame to lose all that info coming from device.
I've read of possibility to increase the buffer, but that is beyond my capabilities.
The biggest problem is how to detect 'end of message', I simply can't catch that info!

  1. I need to send "0XR" command every time when I want new data from Vaisala. So, whenever I read one set of data, I need to send new request (pool the data) in order to receive new set of data. My idea is to set the delay at the end of loop().

My idea is that you look at, understand, and embrace the idea of the blink without delay example.

Echo each character read from the device to the Serial Monitor, as both a character and as a HEX value. I think pretty quickly, you'll get a handle on the output.

And forget about any use of delay(). Use millis() and a stored time (last time you sent data) to determine if it is time to send again.

This only works if length of data is smaller than 63 bytes, if length is larger (in my case, each received message is between 150 and 170 bytes long, depending on measured values), everything falls apart

You can read serial data orders of magnitude faster than it can be received. If you are having troubles storing the data as fast as it can be read, you are storing it wrong.

I think I've understood your point regarding delay(), and will try to switch to millis().
If serial buffer is based on FIFO, I don't see any problem about incoming data length, as long as there is incoming data my 'while available()>0' condition should be TRUE, and my 'inData char array' should be populated properly. However, the data is coming very fast and if I print the value of 'available()' in Serial monitor I can see that it is always begins with 63 and counts down to 0, so the buffer is read OK and sketch is working good if data is less than 63 bytes. If data is more than 63 bytes, I can't understand what is happening :frowning:

Forgive my lack of knowledge, but I'm eager to get this into my head and try to learn what is going on :blush:

However, the data is coming very fast

But not faster than it is possible for the Arduino to read it.

However, the data is coming very fast and if I print the value of 'available()' in Serial monitor I can see that it is always begins with 63 and counts down to 0

Then, you are diddling around somewhere, before getting back to reading data. It is impossible for 63 or more characters to arrive in one iteration of loop(), unless something is causing a delay().

If data is more than 63 bytes, I can't understand what is happening

Would you like us to guess, or would you rather post your code?

Here is a temporary test sketch (just to solve the Vaisala communication part) and if this part doesn't work properly there's no point to continue with rest of code features (RTC, SD Card, LCD). I've removed delay() and used millis() and that part is working OK (thanks PaulS!!).

#include <SoftwareSerial.h>

#define EOD '\n' // EOD - end of data marker

boolean ended = false;

long previousMillis = 0; // to store when was the last time data request have been sent
long interval = 5000; // how often should data be requested

char *command = "0R0"; //string to request data from sensor
char inData[200]; // char array for storing received bytes
byte i; // byte type is enough for storing received string
SoftwareSerial vaisala(2, 3); // RX, TX
 
void setup()
{
  Serial.begin(19200);
  vaisala.begin(19200);
}
 
void loop()
{
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval)
  {
    vaisala.println(command); // request data from Vaisala     
    previousMillis = currentMillis;
  }
  
  while(vaisala.available() > 0)
  {
    char inChar = vaisala.read();
    if(inChar == EOD)
    {
       ended = true;
       break;
    }
    else
    {
      if(i < 163)
      {
        inData[i] = inChar;
        i++;
        inData[i] = '\0';
      }
    }
  }
  if(ended)
  {
    Serial.println(inData);
    // Reset for the next packet
    ended = false;
    i = 0;
    inData[i] = '\0';
  }
}

This is what Vaisala have sent:
0R0,Dn=164D,Dm=192D,Dx=227D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=49.6P,Pa=1010.0H,Rc=0.00M,Rd=0s,Ri=0.0M,Hc=0.0M,Hd=0s,Hi=0.0M,Th=23.8C,Vh=0.0N,Vs=14.4V,Vr=3.501V

And this is the only data visible in Serial monitor (only 3 lines of data, received over a period of couple of minutes, but Arduino have requested the data every 5 seconds, so it shoud be many more lines in Serial monitor. If I wait longer, Serial monitors shows new line with similar incorrect data):

0R0,Dn=162D,Dm=175D,Dx=188D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=49.900=,,ih==r
0R0,Dn=190D,Dm=198D,Dx=212D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=49.91=d0MHhhsVV0R0,Dn=150D,Dm=167D,Dx=190D,Sn=0.0M,Sm=0.1M,Sx=0.1M,Ta=23.8C,Ua=49.9..0HH==01=0R0,Dn
0R0,Dn=150D,Dm=174D,Dx=207D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=50.11R,i.sMC,V00R0,Dn=153D,Dm=190D,Dx=212D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=50.11==0MHThsr0R0,D

Just for reference, Vaisala is repeating a command in its response (in this case 0R0) and every line in Serial monitor is starting OK, but as you go further, errors are starting to happen. My conclusion is that the problem lies in EOD (CR+LF) detection. Other than that I'm in the dark, so please advise, thanks!

char inData[200]; // char array for storing received bytes

      if(i < 163)
      {
        inData[i] = inChar;
        i++;
        inData[i] = '\0';
      }

You have a 200 element array that you are leaving the last 36 elements unused. Why is that?

long previousMillis = 0; // to store when was the last time data request have been sent
long interval = 5000; // how often should data be requested

  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval)
  {

Why are you mixing signed and unsigned?

  1. My understanding is that I just need to set enough "places" in array so [200] is enough, I didn't know that it's wrong to actually have less than maximum in an array (if it is properly ended with a '\0'). Anyway, even if I match these two (array[xxx] and counter i<(xxx-1)), result is same.
  2. I didn't bother to check why "blink / no delay" example is using "unsigned", I've just copied piece of code and this part is working like a charm, command is sent every X seconds.

Every piece of code I've found is working OK if Vaisala response is in the limits of 63 bytes!
I've tried a bunch of other approaches to capture 162 bytes as one record, but in all of them I can't detect EOD byte, to be exact, I never enter into "if (inChar == '\n') part of code. I'm starting to doubt the information in Vaisala documentation about CR/LF at the end of each response, but on the other hand, if I capture the data using some terminal application (Tera Term), and import that data into "Notepad++", CR+LF is clearly visible :roll_eyes:

Here is another test sketch (I'm sending the command to Vaisala and the response is less than 63 bytes, all is working OK).
Whit this sketch I wanted to check if there is CR+LF at the end of response, and I'm 100% sure that it is there (CR+LF).
I'm using "Serial.print" command, and each response is printed on a new line, so CR+LF is there !

#include <SoftwareSerial.h>
SoftwareSerial vaisala(2, 3); // RX, TX
long previousMillis = 0; // to store when was the last time data request have been sent
long interval = 5000; // how often should data be requested
char *command = "0XU"; //string to request data from sensor
byte i=0;
char inData[200];
boolean ended = false;


void setup (){
  Serial.begin(19200);
  Serial.flush();
  vaisala.begin(19200);
  vaisala.flush();
}

void loop (){
  
  long currentMillis = millis();
  if(currentMillis - previousMillis > interval)
  {
    vaisala.println(command); // request data from Vaisala     
    previousMillis = currentMillis;
  }
  while (vaisala.available()>0){
    char inByte = vaisala.read();
    inData[i] = inByte;
    /* response is less than 63 bytes, 
    CR+LF is at the end of each response,
    and in Serial monitor each new line is OK,
    so CR+LF is there 100%, if there was no CR+LF,
    each responce would be printed on same line*/
    Serial.print(inData[i]); 
    i++;
  }
  i=0;
  inData[i] = '\0';
}

In the following image, I present the output from "Vaisala monitor" and "Serial monitor". If I could only rewrite the above code to work with more than 63 bytes... :blush:

I've made some progress by decreasing baud rate to 9600 for "SoftwareSerial" interface (vaisala). I've been going through code and since I wasn't able to find what is wrong, I'v tried lower baud rate and it started to work, I can capture entire response from device and almost never have wrong data (sometimes I get "#" instead of something else, eg. it should be "D", but "#" is written into log file.
As Paul suggested, I've played with sprintf() and it is OK for constructing my SD file name. I've tried to use the same approach for constructing the "time stamp" and that isn't working 100%, the problem is that for example "15:09" is printed as "15:9", "15:00" is printed as "15:0", ... :~). I can't explain in a better way, sorry :blush:. I'm assuming that it has something to do with INTs to CHAR, but I can't figure out how to insert those "0". When I import my log file into "spreadsheet app" it automatically adds these missing "0", but I think it shouldn't be left like this.
Another issue I'm facing is that when I power up my logger, "time stamp" in front of Vaisala response is printed OK, and in the next pass through loop "time stamp" gets a LF at the end (I don't know why) as shown in following picture:

Why is it that the first line is OK, and after that, there's a LF?
Thanks in advance!!!

#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"
#include <SD.h>
#include <LiquidCrystal.h>
#include <SoftwareSerial.h>

RTC_DS1307 RTC;
char filename[] = "00000000.TXT"; 
char date_time[] = "2000/12/31,12:00";
const int chipSelect = 4;      // CS for SD card
LiquidCrystal lcd(14,15,5,6,7,8); // RS,EN,D4,D5,D6,D7
SoftwareSerial vaisala(2, 3); // RX, TX

long previousMillis = 0; // to store when was the last time data request have been sent
long interval = 5000; // how often should data be requested
char *req_data = "0R0"; //string to request data from sensor
byte index=0;
char inData[200];

void setup (){
  pinMode(14, OUTPUT); // RS for LCD, Ethernet Shield present, there's not enough digital pins
  pinMode(15, OUTPUT); // EN for LCD, Ethernet Shield present, there's not enough digital pins
  lcd.begin(16,2);
  Wire.begin();
  Serial.begin(9600);
  vaisala.begin(9600);
  lcd.print(" Vaisala WXT520 ");
  lcd.setCursor(0,1);
  lcd.print(" data logger v1 ");
  delay(3000);
  if (! RTC.isrunning()) {
    lcd.clear();
    lcd.print("RTC not OK");
    Serial.println("RTC is NOT running!");
    while(1);
  }
  //RTC.adjust(DateTime(__DATE__, __TIME__)); // uncoment to set the date and time (only when uploading the sketch)
  delay(100);
  
  Serial.print("Initializing SD card...");
  lcd.clear();
  lcd.print("SD card init...");
  delay(1000); // to be able to see the message
  
  pinMode(10, OUTPUT); // default CS pin (Ethernet Shield)
 
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    lcd.clear();
    lcd.print("SD error !!!");
    Serial.println("Card failed, or not present");
    while(1);
  }
  Serial.println("card initialized.");
  lcd.clear();
  lcd.print("SD card OK!");
  delay(1000); // to be able to see the message
  
} // end of setup()

void loop (){
  
  long currentMillis = millis();
  if(currentMillis - previousMillis > interval)
  {
    vaisala.println(req_data); // request data from Vaisala     
    previousMillis = currentMillis;
  }
  
  if (vaisala.available()){
    while (vaisala.available()){
    char inByte = vaisala.read();
    if (inByte == '\r'){ // if EOD is detected
      getFilename(filename); // call method that constructs the file name
      File dataFile = SD.open(filename, FILE_WRITE);
      if (dataFile)
        {
          lcd.clear();
          lcd.print("Receiving data");
          delay(300); // to stop LCD flickering
        }
         // if the file isn't open, pop up an error:
        else
        {
          lcd.clear();
          lcd.print(" File error ! ");
          while(1);
        }
      timestamp(date_time); // call method for creating timestamp
      dataFile.print(date_time);
      dataFile.println(inData); // print data from char array
      dataFile.close(); // close file
      inData[index] = '\0'; // erase char array
      index=0; // reset array index
      break; // exit while loop
    }
    else{ //write bytes from buffer
      inData[index] = inByte; // update char array
      index++; // increase index counter
      inData[index] = '\0'; // finish array so it qualify as string
    }
  } // end of while loop
 } // end of if(vaisala.available)
} // end of loop()

// method for constructing file name
void getFilename(char *filename) {
  DateTime now = RTC.now(); 
  int year = now.year(); 
  int month = now.month(); 
  int day = now.day();
  sprintf(filename,"20%d%d%d%d%d%d.TXT",(year-2000)/10,year%10,month/10,month%10,day/10,day%10);
  return;
}

// method for creating timestamp string
void timestamp(char *date_time){
  DateTime now = RTC.now(); // collect date and time data
  int year = now.year(); 
  int month = now.month(); 
  int day = now.day();
  int hour = now.hour(); 
  int minute = now.minute(); 
  sprintf(date_time,"%d/%d/%d,%d:%d,",year,month,day,hour,minute);
  return;
}