[solved]Rasperry Pi + Relay + Arduino feedback loop, Relay starts switching...

Observed behavior:
The relay switches on and off approx once per second after a random amount of time(usually 1-2 hours).

Circuit:
Arduino, Raspberry pi on same 5V buck converter from 12V power supply
Relays on separate 5V wall wart
Relays are opto-coupled, board from amazon
https://www.amazon.com/dp/B072K5NQQW/?coliid=I2FL01CS6YEZEW&colid=UBVRGM199GXE&psc=1&ref_=lv_ov_lig_dp_it

Relay switch 120V AC fridge load

The raspberry pi controls arduino via serial.
of format <1,1,255,255>
where <relay 1(unused), relay 2(fridge), pwm 1, pwm 2>

Arduino code:
It uses a non-blocking serial parser I found somewhere.

#include <DallasTemperature.h>
#include <OneWire.h>
#include <DHT.h>


int fridgePin = 4;
int heaterPin = 2;

int humidPin = 3;
int heaterFanPin = 6;

int tempsPin = 7;

//Related to Temp and hum sensors
int DHT1Pin = 10;
int DHT2Pin = 9;
#define DHTTYPE DHT22
DHT dht1(DHT1Pin, DHTTYPE);
DHT dht2(DHT2Pin, DHTTYPE);
float dht1Hum = 0;
float dht1Temp = 0;
float dht2Hum = 0;
float dht2Temp = 0; 

// Related to temp probes
#define ONE_WIRE_BUS 7
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
float T1 = 0;
float T2 = 0;
float T3 = 0;



bool fridgeState = LOW;
bool heaterState = LOW;
int humidityPower = 0;
int heaterFanSpeed = 0;

///// Related to Serial Comm
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
String s = String(0);
boolean newData = false;
/////





void setup() {
 // put your setup code here, to run once:

 pinMode(fridgePin, OUTPUT);
 pinMode(heaterPin, OUTPUT);
 pinMode(humidPin, OUTPUT);
 pinMode(heaterFanPin, OUTPUT);

 dht1.begin();
 dht2.begin();
 sensors.begin();

 Serial.begin(115200);
 //Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
 //Serial.println("Enter data in this style <HelloWorld, 12, 24.7>  ");
 //Serial.println();

}

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

 analogWrite(heaterFanPin, heaterFanSpeed);
 //digitalWrite(heaterFanPin, HIGH);
 analogWrite(humidPin, humidityPower);
 digitalWrite(fridgePin, fridgeState);
 digitalWrite(heaterPin, heaterState);

 recvWithStartEndMarkers();
 if (newData == true) {
   strcpy(tempChars, receivedChars);
   // this temporary copy is necessary to protect the original data
   //   because strtok() used in parseData() replaces the commas with \0
   parseData();
   //showParsedData();
   newData = false;
 }

 dht1Hum  = dht1.readHumidity();
 dht1Temp = dht1.readTemperature();
 dht2Hum  = dht2.readHumidity();
 dht2Temp = dht2.readTemperature();

 sensors.requestTemperatures();
 T1 = sensors.getTempCByIndex(0);
 T2 = sensors.getTempCByIndex(1);
 T3 = sensors.getTempCByIndex(2);
 //  Serial.print(T1);
 //  Serial.print(" ");
 //  Serial.print(T2);
 //  Serial.print(" ");`
 //  Serial.println(T3);
 //  Serial.print(dht1Hum);
 //  Serial.print(" ");
 //  Serial.println(dht1Temp);
 //  Serial.print(dht2Hum);
 //  Serial.print(" ");
 //  Serial.println(dht2Temp);


 s = "<" + String(dht1Hum) + ","  + String(dht2Hum) + "," + String(dht1Temp) + "," + String(dht2Temp) + "," + String(T1) + "," + String(T2) + "," + String(T3) + ">";
 Serial.println(s);



}

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

 //strtokIndx = strtok(tempChars, ",");     // get the first part
 //pullRequested = atoi(strtokIndx);

 strtokIndx = strtok(tempChars, ",");
 heaterState = atoi(strtokIndx);

 strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
 fridgeState = atoi(strtokIndx);     // convert this part to an integer

 strtokIndx = strtok(NULL, ",");
 heaterFanSpeed = atoi(strtokIndx);// convert this part to an integer

 strtokIndx = strtok(NULL, ",");
 humidityPower = atoi(strtokIndx);// convert this part to an integer


}

//============

void showParsedData() {
 Serial.print("heater state ");
 Serial.println(heaterState);
 Serial.print("fridgeState ");
 Serial.println(fridgeState);
 Serial.print("heaterFanSpeed ");
 Serial.println(heaterFanSpeed);
 Serial.print("humidityPower ");
 Serial.println(humidityPower);
}

I send the arduino the control string <1,1,255,255> every time the arduino has finished reporting its data from the sensors.

I first thought the relays were killing the arduino repeatedly, which would turn the relays off, then arduino on and relay on, then arduino off and relay off, etc. etc.
So I placed the relay coils on a separate 5V source, since it was previosly on the same 5V buck converter as the raspi and the arduino.

I'm thinking this behavior may be related to the blocking functions in DHT22 reads and the serial input buffer overflowing?
I will implement a blocking serial read and parse.

Code tags would be nice.

You're using a bunch of String objects here:

s = "<" + String(dht1Hum) + ","  + String(dht2Hum) + "," + String(dht1Temp) + "," + String(dht2Temp) + "," + String(T1) + "," + String(T2) + "," + String(T3) + ">";
  Serial.println(s);

They're likely to mess things up over time and that fits what you observe here. Use plain old C strings instead. Frankly, I didn't actually inspect your code closely - just looked for the word String and once I found it, stopped looking for any other possibilities.

I deleted the string objects, implementing just Serial.print() instead, as well as forcing the reads only once a command has been recieved, yet the issue persists(random cycling of the relay) even after 10 hours.

#include <DallasTemperature.h>
#include <OneWire.h>
#include <DHT.h>


int fridgePin = 4;
int heaterPin = 2;

int humidPin = 3;
int heaterFanPin = 6;

int tempsPin = 7;

//Related to Temp and hum sensors
int DHT1Pin = 10;
int DHT2Pin = 9;
#define DHTTYPE DHT22
DHT dht1(DHT1Pin, DHTTYPE);
DHT dht2(DHT2Pin, DHTTYPE);
float dht1Hum = 0;
float dht1Temp = 0;
float dht2Hum = 0;
float dht2Temp = 0;

// Related to temp probes
#define ONE_WIRE_BUS 7
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
float T1 = 0;
float T2 = 0;
float T3 = 0;



bool fridgeState = LOW;
bool heaterState = LOW;
int humidityPower = 0;
int heaterFanSpeed = 0;

///// Related to Serial Comm
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
String s = String(0);
boolean newData = false;
/////





void setup() {
  // put your setup code here, to run once:

  pinMode(fridgePin, OUTPUT);
  pinMode(heaterPin, OUTPUT);
  pinMode(humidPin, OUTPUT);
  pinMode(heaterFanPin, OUTPUT);

  dht1.begin();
  dht2.begin();
  sensors.begin();

  Serial.begin(115200);
  //Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
  //Serial.println("Enter data in this style <HelloWorld, 12, 24.7>  ");
  //Serial.println();

}

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

  analogWrite(heaterFanPin, heaterFanSpeed);
  //digitalWrite(heaterFanPin, HIGH);
  analogWrite(humidPin, humidityPower);
  digitalWrite(fridgePin, fridgeState);
  digitalWrite(heaterPin, heaterState);

  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    // this temporary copy is necessary to protect the original data
    //   because strtok() used in parseData() replaces the commas with \0
    parseData();
    //showParsedData();
    newData = false;


    dht1Hum  = dht1.readHumidity();
    dht1Temp = dht1.readTemperature();
    dht2Hum  = dht2.readHumidity();
    dht2Temp = dht2.readTemperature();

    sensors.requestTemperatures();
    T1 = sensors.getTempCByIndex(0);
    T2 = sensors.getTempCByIndex(1);
    T3 = sensors.getTempCByIndex(2);
    //  Serial.print(T1);
    //  Serial.print(" ");
    //  Serial.print(T2);
    //  Serial.print(" ");`
    //  Serial.println(T3);
    //  Serial.print(dht1Hum);
    //  Serial.print(" ");
    //  Serial.println(dht1Temp);
    //  Serial.print(dht2Hum);
    //  Serial.print(" ");
    //  Serial.println(dht2Temp);


    //s = "<" + String(dht1Hum) + ","  + String(dht2Hum) + "," + String(dht1Temp) + "," + String(dht2Temp) + "," + String(T1) + "," + String(T2) + "," + String(T3) + ">";

    Serial.print("<");
    Serial.print(dht1Hum);
    Serial.print(",");
    Serial.print(dht2Hum);
    Serial.print(",");
    Serial.print(dht1Temp);
    Serial.print(",");
    Serial.print(dht2Temp);
    Serial.print(",");
    Serial.print(T1);
    Serial.print(",");
    Serial.print(T2);
    Serial.print(",");
    Serial.print(T3);
    Serial.println(">");

    //Serial.println(s);

  }

}

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

  //strtokIndx = strtok(tempChars, ",");     // get the first part
  //pullRequested = atoi(strtokIndx);

  strtokIndx = strtok(tempChars, ",");
  heaterState = atoi(strtokIndx);

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  fridgeState = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  heaterFanSpeed = atoi(strtokIndx);// convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  humidityPower = atoi(strtokIndx);// convert this part to an integer


}

//============

void showParsedData() {
  Serial.print("heater state ");
  Serial.println(heaterState);
  Serial.print("fridgeState ");
  Serial.println(fridgeState);
  Serial.print("heaterFanSpeed ");
  Serial.println(heaterFanSpeed);
  Serial.print("humidityPower ");
  Serial.println(humidityPower);
}

Also, the serial parser is from the Serial Input Basics Thread herehttps://forum.arduino.cc/index.php?topic=288234.0

Discovered issue in my event scheduling inside my python application causing the control script to be sent rapidly. Will report back after another 12 hour test if this resolved the issue.

issue resolved after having arduino perform a reading only after receiving a control string, and only sending a control string after a reading has been received.

I found my old Python code on a RPi for serial, see attachment.

LidarPythonCode.txt (49.6 KB)