Nano with Node MCU - IOT project

I am using a Nano to acquire three analog channels which are basically three phase voltage values. This information is then sent by a Software Serial link to a Node MCU ESP8266 board which then posts it to the ThingSpeak server.

The Nano sends a 13 byte data in the format <230,230,230> once every 30 sec.
The Node MCU reads this using the non blocking serial read with start./end markers ( thanks to Robin !) and parses the data and posts to the cloud. Once every 60 second. So there is minimum one set of valid data.

Problem : The setup works most of the time very well but fails the rest of the time posting null data. I know this is an asynchronous data transfer. earlier I tried to send a character from Node MCU to Nano requesting for data. But that never could be made to work.

I know i will need to post both the Nano and Node MCU codes for study... but before that i wanted to know if there is a basic flaw in the methodology i described. Not that it fails totally .... just that it randomly fails. I have independently checked following :

  • Nano sending data in right format once every 30 sec.
  • Node MCU waking and connecting to WiFi once every 60 sec and also posting to cloud. Except that is some cases it posts null data.
  • I am not clear what happens to the Serial Rx buffer in Node MCU when its sleeping

Any pointers to possible traps ?

OK managed to resolve the issue of missing values - brought in a handshake protocol. When the Node MCU is connected to WiFi it sends a "z" to the Nano via Serial and the Nano in turn sends the last saved phase voltage.

But now i have a new problem... the phase voltage reported by the Nano is very high ... like the actual is 232 Volts and it is reading it as 270 V. And this happened only after i changed the data transfer between Nano and Node MCU as a handshake. I know i am missing something but not sure what... the code at the Nano is as below :

#include "RunningAverage.h"
#include <SoftwareSerial.h>

int RA_SampleSize = 10;
const int rPhase = A0;                  // Analog pins to use.
const int yPhase = A1;
const int bPhase = A2;

int refVolts ;                          // Holder for MCU  Vcc value
int noOfSamples = 300;
int sampleCount ;

int rVoltRawCount = 0;                 // Variable to hold raw AI count
int yVoltRawCount = 0;
int bVoltRawCount = 0;

int rVoltAvgCount = 0;                 // Variable to hold averaged AI count
int yVoltAvgCount = 0;
int bVoltAvgCount = 0;

int rPhaseDcV = 0 ;                    // Variable to hold the DC Volt on analog Pin
int yPhaseDcV = 0 ;
int bPhaseDcV = 0 ;

int rPhaseVoltTemp = 0;                // Variable to hold Temp Voltage value
int yPhaseVoltTemp = 0;
int bPhaseVoltTemp = 0;

int rPhaseVolt = 0;                     // Variable to hold actual Voltage value
int yPhaseVolt = 0;
int bPhaseVolt = 0;

long BaudRate = 9600;

unsigned long bgVoltMillis, bgVoltInterval = 60000;
unsigned long anaAcqMillis, anaAcqInterval = 100;


RunningAverage RA_rVoltCount(RA_SampleSize);
RunningAverage RA_yVoltCount(RA_SampleSize);
RunningAverage RA_bVoltCount(RA_SampleSize);

SoftwareSerial softSerial(2, 3);       // RX, TX (to connect to Tx , RX of remote unit)

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void setup() {

  Serial.begin (BaudRate);
  Serial.println(F("*** Starting MainsPhaseMonitor *** "));
  softSerial.begin(9600);

  RA_rVoltCount.clear();
  RA_yVoltCount.clear();
  RA_bVoltCount.clear();

  bgVoltMillis = millis();
  anaAcqMillis = millis();

  refVolts = getBandgap();

  RA_rVoltCount.clear();
  RA_yVoltCount.clear();
  RA_bVoltCount.clear();
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void loop() {

  if ( millis() - bgVoltMillis > bgVoltInterval ) {
    bgVoltMillis = millis();
    refVolts = getBandgap();                    //Once a minute update the refVolts
  }

  acquirePhaseVolts();
  
  if ( sampleCount > noOfSamples ) {
    sampleCount = 0;
    rPhaseVolt = rPhaseVoltTemp ;
    yPhaseVolt = yPhaseVoltTemp ;
    bPhaseVolt = bPhaseVoltTemp ;
    RA_rVoltCount.clear();
    RA_yVoltCount.clear();
    RA_bVoltCount.clear();
  }

  if ( softSerial.available() ) {
    char request = softSerial.read() ;
    if ( request == 'z') updateNodeMCU();      // Send data to node MCU
  }

}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

// Function to Acquire and average three analog channels

void acquirePhaseVolts () {

  if ( millis() - anaAcqMillis > anaAcqInterval ) {

    anaAcqMillis = millis();

    sampleCount++;
    
    rVoltRawCount = analogRead(rPhase);            // Read the analog input counts..
    yVoltRawCount = analogRead(yPhase);
    bVoltRawCount = analogRead(bPhase);

    RA_rVoltCount.addValue(rVoltRawCount);         // Add it to the previous value
    RA_yVoltCount.addValue(yVoltRawCount);
    RA_bVoltCount.addValue(bVoltRawCount);

    rVoltAvgCount = RA_rVoltCount.getAverage();    // Now get the average count value
    yVoltAvgCount = RA_yVoltCount.getAverage();
    bVoltAvgCount = RA_bVoltCount.getAverage();

    rPhaseDcV = map( rVoltAvgCount, 0, 1023, 0, refVolts);  // Get the actual DC volt on analog pins
    yPhaseDcV = map( yVoltAvgCount, 0, 1023, 0, refVolts);
    bPhaseDcV = map( bVoltAvgCount, 0, 1023, 0, refVolts);

    rPhaseVoltTemp = map( rPhaseDcV, 0, refVolts, 0, 300);      // Map it to Incoming AC volts
    yPhaseVoltTemp = map( yPhaseDcV, 0, refVolts, 0, 300);
    bPhaseVoltTemp = map( bPhaseDcV, 0, refVolts, 0, 300);

  }
}

//**********************************************

// Function to update the ESP Node MCU with acquired data

void updateNodeMCU () {

  softSerial.print( "<");
  softSerial.print(rPhaseVolt);
  softSerial.print(",");
  softSerial.print(yPhaseVolt);
  softSerial.print(",");
  softSerial.print(bPhaseVolt);
  softSerial.print( ">");

}

//**************************************************

// Function to return the Vcc Volts x 100 to maintain precision

int getBandgap(void) {

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    const long InternalReferenceVoltage = 1078L;  // Adjust this value to your MEGA boards specific internal BG voltage x1000
    ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (0 << MUX5) | (1 << MUX4) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
#else
    const long InternalReferenceVoltage = 1072L;  // Adjust this value to your 168/328 boards specific internal BG voltage x1000
    ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
#endif

    delay(10);                                    // Let mux settle a little to get a more stable A/D conversion

    ADCSRA |= _BV( ADSC );                        // Start conversion
    while ( ( (ADCSRA & (1 << ADSC)) != 0 ) );
    int results = (((InternalReferenceVoltage * 1023L) / ADC) + 5L) / 10L; // Scale the value
    return results;
  }

Not attaching the Node MCU code as i have seen it is posting exactly what it is reading on Serial.