Displaying Serial data to web page

I'm attempting to gather data from one Arduino via serial and display it on a second that is running a web server. Initially I was doing this using a string on the web Arduino, but had lots of mis-reads. I did lots of reading and searching and found examples of code (probably written by some of you reading this) that uses char arrays.

I have 2 problems that are not critical, but are annoyances and I don't understand how to fix them (Like most people I am a beginner at programming).

  • If I hit the "Refresh" button on my web page (not browser) the page reloads, but without data. If I hit it again, I get data.

  • If I repeatedly (and quickly) click the "Refresh" button to get data, eventually I get back partial data. It's almost as if the "Weather arduino was in the middle of sending the data, then stopped and resent it.

I think both of these problems are related to somehow not fully receiving the data before displaying it, but I'm at a loss as to how to fix it. I think the 2 clicks to refresh means that on 2nd click I'm really displaying the data from the first click.

I tried inserting delay() statements in various locations, but that did not help, so after much more reading I gathered that I should be using millis(). While that works for a delay, it doesn't appear to solve my problem. (or maybe I don't understand where to place them?)

The Weather Arduino code is the code from this page: https://learn.sparkfun.com/tutorials/weather-station-wirelessly-connected-to-wunderground https://github.com/sparkfun/Wimp_Weather_Station/blob/master/Wimp_Weather_Station.ino

The to Uno's are connected serially to pins 0 and 1

My code is too long to show inline, so I have attached it. [removed attachment as AWOL posted it for me]

If you have thoughts of how I should go about fixing this, please share!

Thanks, Joel

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//byte ip[] = { 192, 168, 2, 201 };   // static ip of Arduino
//byte gateway[] = { 192, 168, 2, 254 };  // gateway address
//byte subnet[] = { 255, 255, 255, 0 };  //subnet mask
EthernetServer server(80);   //web server port

//these variables are for parsing & display
const byte numChars = 1000;
char receivedChars[numChars];
char winddir[32] = {0};
char windspeedmph[32] = {0};
char windgustmph[32] = {0};
char windgustdir[32] = {0};
char windspdmph_avg2m[32] = {0};
char winddir_avg2m[32] = {0};
char windgustmph_10m[32] = {0};
char windgustdir_10m[32] = {0};
char humidity[32] = {0};
char tempf[32] = {0};
char rainin[32] = {0};
char dailyrainin[32] = {0};
char pressure[32] = {0};
char batt_lvl[32] = {0};
char light_lvl[32] = {0};
char recvChar;
boolean newData = false;

unsigned long interval=2000; //time needed to wait (in milliseconds)
unsigned long previousMillis=0; // millis() returns an unsigned long.

void setup() {
  Serial.begin(9600);
  // put your setup code here, to run once:

  //start Ethernet
 // Ethernet.begin(mac, ip, gateway, subnet);
  Ethernet.begin(mac);  // mac only means Ethernet will DHCP.

}
EthernetClient client;
void loop() {
  // put your main code here, to run repeatedly:

  //start the string serial receiver/parser
  recvWithStartEndMarkers();

  //start the web server (note, the following commented-out line is broken up outside the loop() so that showParsedData() can use "client."
  //EthernetClient client = server.available();
  client = server.available();
  if ((unsigned long)(millis() - previousMillis) >= interval) {
              previousMillis = millis();
  if (client) {
    // an http request ends with a blank line
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //The next block of code figures out if we have been asked to send any control codes to the weather station
        String header(c);
        if (header.indexOf("!") > -1) {
            //get data from serial
            Serial.write("!"); //Tell the Weather Arduino that you want fresh data! (This will trigger recvWithStartEndMarkers() to run as it will be sent data via serial)
        }
        if (header.indexOf("@") > -1) {
          //midnight reset (this will need setup for another machine to do this via cron)
          Serial.write("@");
        }
        if (header.indexOf("%") > -1) {
          Serial.write("#"); //send hardreset/reboot
        }
        
        header=""; //clearing string for next read
         if (c == '\n') {
           //if ((unsigned long)(millis() - previousMillis) >= interval) {
           //   previousMillis = millis();
     
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println();
          client.println("<head><title>ClarkNet Manhouse Weather Station</title></head>");
          client.println("<html>"); 
          client.println("
<a href=\"/!\">Get Data</a>");  //Have to escape the ""'s aorund the link /!
          client.println("
<a href=\"/@\">Reset Daily</a>");
          client.println("
<a href=\"/%\">Reboot Weather Arduino</a>
");
          
          showNewData();          
          client.println("</html>");
          break; 
          //} 
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    
    Ethernet.maintain();
  }
  } 
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '

;
  char endMarker = ‘#’;
  char rc;
 
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = ‘\0’; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}
 
void parseData() {

// split the data into its parts
   
  char * strtokIndx; // this is used by strtok() as an index

//we take the comma separated values and break them apart into their own variables.
  strtokIndx = strtok(receivedChars,",");      // get the first part - the string
  strcpy(winddir, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”); // this continues where the previous call left off
  strcpy(windspeedmph, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(windgustmph, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(windgustdir, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(windspdmph_avg2m, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(winddir_avg2m, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(windgustmph_10m, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(windgustdir_10m, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(humidity, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(tempf, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(rainin, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(dailyrainin, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(pressure, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(batt_lvl, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, “,”);
  strcpy(light_lvl, strtokIndx); // copy it to its variable
}

void showParsedData() {
  client.print("
“);
  client.println(winddir);
  client.print(”
“);
  client.println(windspeedmph);
  client.print(”
“);;
  client.println(windgustmph);
  client.print(”
“);
  client.println(windgustdir);
  client.print(”
“);
  client.println(windspdmph_avg2m);
  client.print(”
“);
  client.println(winddir_avg2m);
  client.print(”
“);
  client.println(windgustmph_10m);
  client.print(”
“);
  client.println(windgustdir_10m);
  client.print(”
“);
  client.println(humidity);
  client.print(”
“);
  client.println(tempf);
  client.print(”
“);
  client.println(rainin);
  client.print(”
“);
  client.println(dailyrainin);
  client.print(”
pressure=");
  client.println(pressure);
  client.print("
“);
  client.println(batt_lvl);
  client.print(”
");
  client.println(light_lvl);
}

void showNewData() {
  if (newData == true) {
    parseData();
    showParsedData();
    newData = false;
  }
}

Thanks for posting the code for me. I was not sure how to get it posted at it's current length. -Joel

If I hit the "Refresh" button on my web page (not browser) the page reloads, but without data. If I hit it again, I get data.

A web page is a stream of bytes rendered by a browser. How can you possibly "hit the refresh button" on a stream of bytes?

I tried inserting delay() statements in various locations, but that did not help,

Of course not.

The to Uno's are connected serially to pins 0 and 1

So you can't debug your code. Not the best idea...

PaulS’s reply made me realize I didn’t explain the functionality very well.

The Arduino powered web page has a link named “Refresh” This link when clicked sends a “!” to the serial bus to ask the sending (weather) Arduino for new data. So in this instance, “Refresh” doesn’t mean to refresh the web page, so much as it means to refresh the data (weather) from the other Arduino.

-Joel

You need to describe much more clearly the whole process that you are trying to achieve.

I am confused about why you have two Arduinos - why not just use one ?

However there should be no problem writing code on Arduino A that sends a request for data to Arduino B.

If this was my project I would hold the latest version of the data on the Arduino that hosts the server so that a request from the browser can be answered directly. I would then have code that updates that data when the other Arduino has new data.

If you want help post the code from both Arduinos.

As @PaulS has said it would be a great help to you if you keep Pins0 and 1 free on both Arduinos for sending debug messages to the Serial Monitor. You should be able to use SoftwareSerial to communicate between the Arduinos.

...R

The Arduino powered web page has a link named "Refresh"

Does the Arduino provide enough voltage and current to "power" your web page? Perhaps you need an external power supply, if your web page sucks to much current.

The Arduino SERVES a web page. It does NOT power it.

This link when clicked sends a "!" to the serial bus

It most certainly does not. The browser submits a GET request that gets to the Arduino via the Ethernet shield, NOT the serial port.

So in this instance, "Refresh" doesn't mean to refresh the web page

That is ALL that it means.

so much as it means to refresh the data (weather) from the other Arduino.

That the one Arduino needs to get data from the other Arduino is completely irrelevant.

Sorry for the confusion.

I didn’t write the code for the Weather (sending) Arduino. It’s from a project posted on SparkFun’s website. Originally the project was designed to use a different 3rd party device (I believe it is called Electric IMP). In their example/build, the Arduino communicates with the IMP via serial. The IMP sends codes (like “!”) via serial to ask the Arduino to do something (like collect and return weather data). The Arduino “listens” for these commands and “responds” back via serial. I’ve attached the sketch below as it is too large to post.

I have 2 Arduinos because when I began adding Web page display code to the sketch of the Weather Arduino, I received compile errors in the IDE that I was low on memory and that stability problems would occur (they did). I had an extra Uno, and knowing that the Weather sketch was engineered to communicate via serial, I figured it would might work to split the gathering of the weather data from the displaying and thus my Web (receiver) sketch was born.

When I connect my computer to the Weather Arduino only via the IDE and using Serial Monitor, I can send the request flag “!” multiple times and as fast as I can. I always get a valid response string without data corruption. The data returned looks like this:

$,winddir=270,windspeedmph=0.0,windgustmph=0.0,windgustdir=0,windspdmph_avg2m=0.0,winddir_avg2m=12,windgustmph_10m=0.0,windgustdir_10m=0,humidity=998.0,tempf=-1766.2,rainin=0.00,dailyrainin=0.00,-999.00,batt_lvl=16.11,light_lvl=3.32,#,

This is the same data the Web Arduino expects and I’m attempting to parse and display on the Web page.

I intend for the Web sketch to work like:
I visit Web Arduino IP page to load webpage, then click the “Refresh” link on page. Web Arduino sees the “!” as part of the html GET and then runs the function(s) to get weather data from the Weather Arduino. This is the serial process described above, using the same “!” as a flag. Web Arduino parses the comma separated data (that has “$” start and “#” stop codes) received and displays it in a people friendly view on the web page.

So this does work, just not entirely reliably. On a cold boot/reset of the Web Arduino, I have to click the “Refresh” link on the web page 2 times before it displays data. Additionally, if I rapidly click the same link, I sometimes get incorrect data (values in wrong places, missing values, etc).

I suspect that I have to click the page 2 times because I’m displaying the data too quickly and it has not been fully received from the Weather Uno before being displayed by the Web Uno. I suspect the data corruption is really the same problem, except that new weather data has been requested before the previous data has been fully received and I end up with a partial chunk of data followed by an additional full chunk of data.

My thought (and why I’ve posted here) is that I need to introduce some timing/delay into the Web sketch to properly allow for the data transfer and parsing before trying to display the data. This is where I get lost and am asking for help.

Thanks,
Joel

Wimp_Weather_Station.ino (20.8 KB)

From your example it looks like the data is prefixed by a $ and terminated with a # (although you have a comma after the #)

The 3rd example in Serial Input Basics is designed to receive that sort of thing. Just change the start- and end-markers to match your system. There is also a parse example - but I'm not sure if you will need that.

...R

On the server, you should separate the request of serial data from the other Arduino from what you return to the client.

When receiving serial data, do not do any parsing/sharing of that data until the complete packet has arrived. Only share the previous packet until you have a whole new packet.

What you are sending via the serial port is WAY more information than needed.

$,winddir=270,windspeedmph=0.0,windgustmph=0.0,windgustdir=0,windspdmph_avg2m=0.0,winddir_avg2m=12,windgustmph_10m=0.0,windgustdir_10m=0,humidity=998.0,tempf=-1766.2,rainin=0.00,dailyrainin=0.00,-999.00,batt_lvl=16.11,light_lvl=3.32,#,

If both ends KNOW that the order of the values will always be the same, the identification stuff is not needed. If the order can change, you can still use much shorter names. A, B, C, D...

It doesn't make sense to have name=value pairs in most, but not all, places.

Below is some “refresh” test code that displays the arduino current analog input pin values. In the code area that gets the analog values, you might put your serial code to get the desired info from a serial connected device. You might save your dynamic memory by using the F() macro for your web page static text. Below is a site that has some more ways to display data.

http://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/web-server-read-switch-automatically-using-AJAX/

// zoomkat's meta refresh data frame test page 5/25/13
// use http://192.168.1.102:84 in your brouser for main page
// http://192.168.1.102:84/data static data page
// http://192.168.1.102:84/datastart meta refresh data page
// for use with W5100 based ethernet shields
// set the refresh rate to 0 for fastest update
// use STOP for single data updates

#include <SPI.h>
#include <Ethernet.h>

const int analogInPin0 = A0;
const int analogInPin1 = A1;
const int analogInPin2 = A2;
const int analogInPin3 = A3;
const int analogInPin4 = A4;
const int analogInPin5 = A5;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // arduino ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
unsigned long int x=0; //set refresh counter to 0
String readString; 

//////////////////////

void setup(){
  Serial.begin(9600);
    // disable SD SPI if memory card in the uSD slot
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  server.begin();
  Serial.println("meta refresh data frame test 5/25/13"); // so I can keep track of what is loaded
}

void loop(){
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
         if (readString.length() < 100) {
          readString += c; 
         } 
        //check if HTTP request has ended
        if (c == '\n') {

          //check get atring received
          Serial.println(readString);

          //output HTML data header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          //generate data page
          if(readString.indexOf("data") >0) {  //checks for "data" page
            x=x+1; //page upload counter
            client.print("<HTML><HEAD>");
            //meta-refresh page every 1 seconds if "datastart" page
            if(readString.indexOf("datastart") >0) client.print("<meta http-equiv='refresh' content='1'>"); 
            //meta-refresh 0 for fast data
            if(readString.indexOf("datafast") >0) client.print("<meta http-equiv='refresh' content='0'>"); 
            client.print("<title>Zoomkat's meta-refresh test</title></head><BODY>
");
            client.print("page refresh number: ");
            client.print(x); //current refresh count
            client.print("

");
            
              //output the value of each analog input pin
            client.print("analog input0 is: ");
            client.print(analogRead(analogInPin0));
            
            client.print("
analog input1 is: ");
            client.print(analogRead(analogInPin1));
                        
            client.print("
analog input2 is: ");
            client.print(analogRead(analogInPin2));
            
            client.print("
analog input3 is: ");
            client.print(analogRead(analogInPin3));
                                    
            client.print("
analog input4 is: ");
            client.print(analogRead(analogInPin4));
            
            client.print("
analog input5 is: ");
            client.print(analogRead(analogInPin5));
            client.println("
</BODY></HTML>");
           }
          //generate main page with iframe
          else
          {
            client.print("<HTML><HEAD><TITLE>Zoomkat's frame refresh test</TITLE></HEAD>");
            client.print("Zoomkat's Arduino frame meta refresh test 5/25/13");
            client.print("

Arduino analog input data frame:
");
            client.print("&nbsp;&nbsp;<a href='http://192.168.1.102:84/datastart' target='DataBox' title=''yy''>META-REFRESH</a>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='http://192.168.1.102:84/data' target='DataBox' title=''xx''>SINGLE-STOP</a>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='http://192.168.1.102:84/datafast' target='DataBox' title=''zz''>FAST-DATA</a>
");
            client.print("<iframe src='http://192.168.1.102:84/data' width='350' height='250' name='DataBox'>");
            client.print("</iframe>
</HTML>");
          }
          delay(1);
          //stopping client
          client.stop();
          //clearing string for next read
          readString="";
        }
      }
    }
  }
}

Thanks to all for the help. I’ve reformed my sketch a little bit and have made things somewhat better and now have an idea where I’m having trouble. I can reproduce the problem, but am not yet sure how to fix it. Any help is appreciated.

First I slimmed down the length of data sent via serial between the devices. I now expect a string like this sent to the receiver:

<180,0.0,0.0,0,0.0,180,0.0,0,50.7,88.0,0.00,0.00,98068.00,11.41,0.63>

to be sent between the two devices.

Following Robin’s post here:

I’m correctly grabbing between the < and > characters. I end up with

180,0.0,0.0,0,0.0,180,0.0,0,50.7,88.0,0.00,0.00,98068.00,11.41,0.63

I have/will attach the web/receiver sketch to the next post for review.

I’ve modified it so that I can see either the raw string of text above in my web browser by using the parseData_fake() and showParsedData_fake() functions. If I use these functions instead of parseData() and showParsedData() my web browser correctly shows the entire string:

180,0.0,0.0,0,0.0,180,0.0,0,50.7,88.0,0.00,0.00,98068.00,11.41,0.63

I can refresh the page as fast as I can click and have no problems. Data is valid and received every time.

If I use the parseData() and showParsedData() functions instead (in order to pick out the individual values to display in a human readable format) I get random data corruption about 50% of the time. It doesn’t matter how fast or slow I refresh my web browser. I’m fairly certain the parsing is what is wrong. Does someone else have an idea of what is wrong with the parser?

Here is an example of the invalid parse attempt: (note the “<180” in batt_lvl)

winddir=180
windspeed=0.0
windgustmph=0.0
windgustdir=0
windspdmph_avg2m=0.0
windir_avg2m=180
windgustmph_10m=0.0
windgustdir_10m=0
humidity=47.6
tempf=86.9
rainin=0.00
dailyrainin=0.00
pressure=98090.50
batt_lvl=11.41<180
light_lvl=0.0

Thanks for any help!
Joel

Here’s the latest code I’m working on:
This posted version has the parseData() and showparsedData() functions currently commented out and am using parseData_fake() and showparsedData_fake() so that I get a working string. toggling these functions will show the problem.

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//byte ip[] = { 192, 168, 2, 201 };   // static ip of Arduino
//byte gateway[] = { 192, 168, 2, 254 };  // gateway address
//byte subnet[] = { 255, 255, 255, 0 };  //subnet mask
EthernetServer server(80);   //web server port

//these variables are for parsing & display
const byte numChars = 125;
char receivedChars[numChars];
char winddir[32] = {0};
char windspeedmph[32] = {0};
char windgustmph[32] = {0};
char windgustdir[32] = {0};
char windspdmph_avg2m[32] = {0};
char winddir_avg2m[32] = {0};
char windgustmph_10m[32] = {0};
char windgustdir_10m[32] = {0};
char humidity[32] = {0};
char tempf[32] = {0};
char rainin[32] = {0};
char dailyrainin[32] = {0};
char pressure[32] = {0};
char batt_lvl[32] = {0};
char light_lvl[32] = {0};
boolean newData = false;
boolean isRefresh = false;

void setup() {
  Serial.begin(9600);
  // put your setup code here, to run once:

  //start Ethernet
  // Ethernet.begin(mac, ip, gateway, subnet);
  Ethernet.begin(mac);  // mac only means Ethernet will DHCP.

}
EthernetClient client;
void loop() {
  // put your main code here, to run repeatedly:

  //start the string serial receiver/parser
  recvWithStartEndMarkers();

  //start the web server (note, the following commented-out line is broken up outside the loop() so that showParsedData() can use "client."
  //EthernetClient client = server.available();
  client = server.available();
  if (client) {
    // an http request ends with a blank line
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //The next block of code figures out if we have been asked to send any control codes to the weather station
        String header(c);
        if (header.indexOf("!") > -1) {
          //get data from serial
          Serial.write("!"); //Tell the Weather Arduino that you want fresh data! 
          //set value for delay later
          isRefresh = true;
        }
        if (header.indexOf("@") > -1) {
          //midnight reset (this will need setup for another machine to do this via cron)
          Serial.write("@");
        }
        if (header.indexOf("%") > -1) {
          Serial.write("#"); //send hardreset/reboot
        }
        
        header=""; //clearing string for next read
        if (c == '\n') {
          // send a standard http response header
          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: text/html"));
          client.println(F("Connection: close"));  // the connection will be closed after completion of the response
          client.println();
          if (isRefresh == true) {
            //refresh the page/redirect to the home page after 1 second
            client.println(F("<head><title>ClarkNet Manhouse Weather Station</title><meta http-equiv=\"refresh\" content=\"2;url=/\" /></head>"));
            isRefresh = false;
          }
          else {
            client.println(F("<head><title>ClarkNet Manhouse Weather Station</title></head>"));
          }
          client.println(F("<html>")); 
          client.println(F("<a href=\"/!\">Get Data</a>
"));  //Have to escape the ""'s aorund the link /!
          client.println(F("<a href=\"/\">Show Data</a>
"));
          client.println(F("<a href=\"/@\">Reset Daily</a>
"));
          client.println(F("<a href=\"/%\">Reboot Weather Arduino</a>

"));

          showParsedData_fake();
          //showParsedData();
                  
          client.println(F("</html>"));
          break; 
        }
      }
    }
    //delay(1);
    // close the connection:
    client.stop();
    
    Ethernet.maintain();
  }
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
        //parseData();
        parseData_fake();  
        
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void parseData_fake() {
  newData = false;
}
  
void parseData() {

  // split the data into its parts
    
  char * strtokIndx; // this is used by strtok() as an index

  //we take the comma separated values and break them apart into their own variables.
  strtokIndx = strtok(receivedChars,",");      // get the first part - the string
  strcpy(winddir, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  strcpy(windspeedmph, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(windgustmph, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(windgustdir, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(windspdmph_avg2m, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(winddir_avg2m, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(windgustmph_10m, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(windgustdir_10m, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(humidity, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(tempf, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(rainin, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(dailyrainin, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(pressure, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(batt_lvl, strtokIndx); // copy it to its variable
  strtokIndx = strtok(NULL, ",");
  strcpy(light_lvl, strtokIndx); // copy it to its variable
  newData = false;
}


void showParsedData_fake() {
  client.println(receivedChars);
}

void showParsedData() {

  client.print(F("
winddir="));
  client.print(winddir);
  client.println(F("
"));
  client.print(F("windspeed="));
  client.print(windspeedmph);
  client.println(F("
"));
  client.print(F("windgustmph="));;
  client.print(windgustmph);
  client.println(F("
"));
  client.print(F("windgustdir="));
  client.print(windgustdir);
  client.println(F("
"));
  client.print(F("windspdmph_avg2m="));
  client.print(windspdmph_avg2m);
  client.println(F("
"));
  client.print(F("windir_avg2m="));
  client.print(winddir_avg2m);
  client.println(F("
"));
  client.print(F("windgustmph_10m="));
  client.print(windgustmph_10m);
  client.println(F("
"));
  client.print(F("windgustdir_10m="));
  client.print(windgustdir_10m);
  client.println(F("
"));
  client.print(F("humidity="));
  client.print(humidity);
  client.println(F("
"));
  client.print(F("tempf="));
  client.print(tempf);
  client.println(F("
"));
  client.print(F("rainin="));
  client.print(rainin);
  client.println(F("
"));
  client.print(F("dailyrainin="));
  client.print(dailyrainin);
  client.println(F("
"));
  client.print(F("pressure="));
  client.print(pressure);
  client.println(F("
"));
  client.print(F("batt_lvl="));
  client.print(batt_lvl);
  client.println(F("
"));
  client.print(F("light_lvl="));
  client.print(light_lvl);
  client.println(F("
"));
}

I think you need if (newData == true) { at the top of your showParsedData() function - and then newData should be set to false at the end of that function and NOT at the end of the parseData() function.

I think they way you are doing things you may be mixing up different sets of data.

...R

R,
Thanks for the quick reply and help. That change has made the code much more reliable. I also took at look at https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay to learn how to delay/limit the request of data

Serial.write("!");

I now only send the request only a max of every 3 seconds and don’t attempt to show data if within the 3 second interval.

I’m still able to get invalid data, but only in infrequent,extreme situations of massive amounts of clicking the “get data” link on the webpage (think rapidly clicking the link about 50 times as fast as you can). I’ve monitored the string sent to the receiver and it has no corruption in it. It’s just the display that gets corrupted. (I wonder, but am not sure, if the problem has more to do with overwhelming the receiver via web traffic and causing significant delays in the processing within the receiver arduino itself. Just a thought, and I don’t necessarily care to know. :slight_smile: )

It should not be a problem since this is outside of the use-case for my weather station project, so I believe it is now “good enough” and will work.

Thanks again for everyone’s help.

-Joel

My final code for future reference is attached (It’s too large to post):

code.ino (9.59 KB)

I think if that was my project I would move all that "client" code from loop() into a function and I would also take the requestSerial() call out of the "client" code. requestWeatherData() would be a better name

My loop() would probably look like this

void loop() {
   requestWeatherData();
   recvWithStartEndMarkers();
   updateClient();
}

...R