Receiving serial data in groups instead of individually

I have two different Vernier science probes connected to a Vernier shield that connects to an Arduino Uno. I have the Uno connected to an ESP8266 via the Tx.

Here is my Uno code:

   String sensor1 ="Conductivity Probe ";
    float interceptSensor1 = 0.0;
    float slopeSensor1 = 960;
    
    String sensor2 ="pH Probe ";
    float interceptSensor2 = 13.720;
    float slopeSensor2 = -3.838;
    
    int timeBetweenReadings = 2000; // in ms
    
    /////////////////////////////////////////
    void setup() 
    {
      Serial.begin(115200); //initialize serial communication at 115200 baud
    }
    
    void loop() 
    {
      
      float analogSensor1 = analogRead(A0);
      float voltageSensor1 = analogSensor1 / 1023 * 5.0;// convert from count to raw voltage
      float sensor1Reading= interceptSensor1 + voltageSensor1 * slopeSensor1; //converts voltage to sensor reading
      String sensor1Output = sensor1 + sensor1Reading;
      Serial.println(sensor1Output);
    
      delay(timeBetweenReadings);// delay in between reads for stability
      
      float analogSensor2 = analogRead(A1);
      float voltageSensor2 = analogSensor2 / 1023 * 5.0;// convert from count to raw voltage
      float sensor2Reading= interceptSensor2 + voltageSensor2 * slopeSensor2; //converts voltage to sensor reading
      String sensor2Output = sensor2 + sensor2Reading;
      Serial.println(sensor2Output);  
      
      delay(timeBetweenReadings);// delay in between reads for stability
      
    }

On the serial monitor every two seconds I get one line of output and it alternates back and forth between the sensors:

Conductivity Probe 807.04

pH Probe 4.12

Conductivity Probe 802.35

pH Probe 4.13

Conductivity Probe 802.35

pH Probe 4.12

Since I've only got a simple serial line to work with but I need to send multiple, different types of data to the ESP8266, my strategy is to send one line (ex. Conductivity Probe 807.04) and use logic on the ESP8226 to parse the string, isolate the float number (807.04), and use Conductivity Probe to determine how that number gets further used (in my case, to publish to an MQTT feed called ElectroConductivity).

The Tx of the Uno + sensors is wired to the Rx of the ESP8266, and here's the ESP8266 code:

void loop() {

  while (Serial.available() == 0) {
  }

  MQTT_connect();

  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(5000))) {
    if (subscription == &onoffbutton) {
      Serial.print(F("Got: "));
      Serial.println((char *)onoffbutton.lastread);
    }
  }

  sensorReading = Serial.readString();
  Serial.println(sensorReading);

The data comes in large groups instead of line by line:

pH Probe 4.12
Conductivity Probe 807.04
pH Probe 4.12
Conductivity Probe 807.04

I'm new to serial comms and Arduino in general. I'm guessing that there's an issue with how serial is read by the ESP8266? My hope was that every time there is a single Serial.println() on the Uno that it would immediately send only that one line to the ESP8266, and the ESP8266 would immediately only receive that one line.

EDIT:

When I use

  sensorReading = Serial.readString();
  Serial.println(sensorReading);

instead my output looks like this:

Conductivity PrpH Probe 4.12

Conductivity Probe 816.42

pH Probe 4.12

Conductivity Probe 825.8Conductivity Probe 821.11

Conductivity Probe 821.11

pH Probe pH Probe 4.12

ConductivitypH Probe 4.12

Using a well-defined message format will make things a whole lot easier.
For example, "<C:807.04>" and "<P:4.12>". By using start and end markers ('<' and '>'), you know that the message was finished, and that you didn't start reading in the middle of a message. The ':' separator separates the different values. You can use the first value to determine whether it was a conductivity or pH value.

Take a look at the 5th example in Robin2's Serial Input Basics.

Pieter

The data comes in large groups instead of line by line:

To avoid needing to re-write a lot of code (which you should do anyway), look at readStringUntil() vs. readString(). You are sending a carriage return and line feed after each group of characters. Make use of that fact on the reading end.

PaulS:
To avoid needing to re-write a lot of code (which you should do anyway), look at readStringUntil() vs. readString(). You are sending a carriage return and line feed after each group of characters. Make use of that fact on the reading end.

I used readStringUntil() and updated my original post.

So now I'm a bit more confused. The code in my OP didn't include all the code in the main loop() function because I didn't think that it would matter, but I've included it back in. Here's the full code in my ESP8266:

void loop() {

  while (Serial.available() == 0) {
  }

  MQTT_connect();

  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(5000))) {
    if (subscription == &onoffbutton) {
      Serial.print(F("Got: "));
      Serial.println((char *)onoffbutton.lastread);
    }
  }

  sensorReading = Serial.readStringUntil('\n');
  Serial.println(sensorReading);

}

The output that I get is highly jumbled, the \n is ignored, etc

ConductivityConductivity Probe 835.19

pH Probe 4.12

Conductivity Probe 830.50

pH pH Probe 4.12

ConpH Probe 4.12

Conductivity Probe 830.5Conductivity Probe 853.96

pH Probe 4.1Conductivity Probe 839.88

pH PropH Probe 4.12

ConductivitypH Probe 4.13

Conductivity Probe 835.19

pH Probe 4.1Conductivity PrpH Probe 4.12

When I comment / remove all of the MQTT stuff everything works just fine. The inputs pop up one by one and aren't jumbled at all.

void loop() {

  while (Serial.available() == 0) {
  }

  sensorReading = Serial.readStringUntil('\n');
  Serial.println(sensorReading);

}

What is it about the MQTT code that's cause the serial input to arrive jumbled?

What is it about the MQTT code that's cause the serial input to arrive jumbled?

Most likely what is happening is that the mqtt code is blocking code, and more serial data is being sent than can be read, so (lots of) data gets lost.

Hand-shaking may be necessary. When the one device needs data, it should ask the other one for it, and wait for a reply. The other one should NOT send data unless data is requested.

mqtt.readSubscription(5000) waits up to 5000 milliseconds for a response. That's fine for a demo program but obviously not for actual working code that has other jobs to do. In Arduino terms, that's like waiting a month by the mailbox to see if a letter arrives.

What if you change it to mqtt.readSubscription(5)? Then you don't take so long waiting and the incoming serial buffer doesn't get filled to overflowing. But does that cause it to miss MQTT messages? I don't know.

Alternatively, if it's absolutely necessary to wait 5000ms and you don't mind missing serial messages during that time, then you just have to get into sync by discarding everything in the serial buffer and waiting for the next character which indicates the start of an incoming message.

const unsigned long MaximumTimeToWaitForSerial = 5000; //milliseconds - how long to wait for serial data
void loop() {

  MQTT_connect();

  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(5000))) {
    if (subscription == &onoffbutton) {
      Serial.print(F("Got: "));
      Serial.println((char *)onoffbutton.lastread);
    }
  }

  while (Serial.available() > 0) {  //discard all the characters in the serial buffer - it will be a mess of partial messages at this point
    Serial.read(); 
  }
  bool FoundValidMessageStart = false;
  unsigned long StartOfWaitForSerial = millis();
  while(!FoundValidMessageStart && millis() - StartOfWaitForSerial < MaximumTimeToWaitForSerial) {
    if(Serial.available() > 0) {  
      if(Serial.read() == '\n') FoundValidMessageStart = true;
    }
  }

  if(FoundValidMessageStart) {
    sensorReading = Serial.readStringUntil('\n');
    Serial.println(sensorReading);
  }

}