user77279: I am experimenting with Aquaponics and since I am a software developer I found it "smart" to use arduino/raspberry in order to control the water flow and not simply use a water pump with mechanical means.
The advantage is that I am able to expand easier the system. The disadvantage is that I haven't yet met the reliability that I would lie to have.
I am a software engineer with basic knowledge in the hardware field. That is why I thought of starting with Raspberry.
Initially I made a setup with a single raspberry PI a few float sensors like this: https://www.hellasdigital.gr/electronics/sensors/humidity-sensor/tank-pool-water-level-liquid-sensor-float-switch/
and relay like this one: https://wiki.52pi.com/index.php/DockerPi_4_Channel_Relay_SKU:_EP-0099
I saw that sometimes the system was hanging with the relays open! This had the side effect to loose water. This is the most precious in aquaponics!
Thus I thought of creating a cluster. Thus I made a cluster of three Raspberrys. The two had the relays and only one PI had the sensors. In order to open the water pump both PIs should have given the green light. This worked better and when one of the PIs hanged then we lost no water.
But again I am thinking that it was not acceptable that the system was hanging so often (at least several times per week). Thus I thought maybe if I use an Arduino for this purpose then this would be better.
Thus this is what I did. I created a simple program (no cluster and a single Arduino). Unfortunately this had even worst results!!!
For the Arduino I used normal 5 Volt relays like this one: https://www.nettop.gr/index.php/hlektronika/relay/8-channel-5v-relay-module-with-light-coupling-5v.html and the same float sensors.
I do not believe that is software related the issue but it must be hardware.
The problem is that my knowledge in the hardware field is limited!
What should I do in order to prevent this? Do you think that is related with the water pumps and the relays ?
The same erroneous behavior happens at both the Raspberry and Arduino, I mean that the relay stays open and the water overflows. For Raspberry I can tell that the system stop to respond, I am sure about it. But for Arduino I cannot say for sure if the whole system was frozen or if input only for the float did not work.
I paste a link to the quick and dirty Arduino code as well for your reference.
The temperature were the systems were operating could be quite hot (30 ~ 48 degrees Celsius) for several hours.
Here is the code for the Arduino:
#define POT_1_FLOAT_SENSOR  2 
#define POT_1_RELAY_1       11     

#define PIPE_1_FLOAT_SENSOR  5 
#define PIPE_1_RELAY_1       9     

#define PIPE_2_FLOAT_SENSOR       3     
#define PIPE_2_RELAY_2      10     

#define PIPE_3_RELAY_3       12    
#define PIPE_3_FLOAT_SENSOR       4     

// pot 1
const unsigned long POT_1_MAX_WATERING_PERIOD = 120000;
const unsigned long POT_1_DRAIN_PERIOD = 70000;

unsigned long pot1StartMillis = 0;
unsigned long pot1DelayStartMillis = 0;

// Pipe 2
const unsigned long PIPE_2_MAX_WATERING_PERIOD = 300000;
const unsigned long PIPE_2_DRAIN_PERIOD = 300000;

unsigned long pipe2DelayStartMillis = 0;
unsigned long pipe2StartMillis = 0;

// Pipe 3
const unsigned long PIPE_3_MAX_WATERING_PERIOD = 760000;
const unsigned long PIPE_3_DRAIN_PERIOD = 300000;
unsigned long pipe3DelayStartMillis = 0;
unsigned long pipe3StartMillis = 0;

// Pipe 1
const unsigned long PIPE_1_MAX_WATERING_PERIOD = 180000;
const unsigned long PIPE_1_DRAIN_PERIOD = 300000;
unsigned long pipe1DelayStartMillis = 0;
unsigned long pipe1StartMillis = 0;



bool pot1RedFlag = false;
bool pot1SetStartTime = false;

bool pipe1RedFlag = false;
bool pipe1SetStartTime = false;

bool pipe2RedFlag = false;
bool pipe2SetStartTime = false;

bool pipe3RedFlag = false;
bool pipe3SetStartTime = false;



void setup() 
{
  Serial.begin(9600);
  // initialize the pushbutton pin as an input:
  pinMode(POT_1_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(POT_1_RELAY_1, OUTPUT);
  digitalWrite(POT_1_RELAY_1, LOW);

  pinMode(PIPE_1_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_1_RELAY_1, OUTPUT);
  digitalWrite(PIPE_1_RELAY_1, LOW);

  pinMode(PIPE_2_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_2_RELAY_2, OUTPUT);
  digitalWrite(PIPE_2_RELAY_2, LOW);

  pinMode(PIPE_3_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_3_RELAY_3, OUTPUT);
  digitalWrite(PIPE_3_RELAY_3, LOW);
  
  pot1StartMillis = millis();
  pipe1StartMillis = millis();
  pipe2StartMillis = millis();
  pipe3StartMillis = millis();
}

void loop() 
{
  checkAbstractWateringTimer(pot1SetStartTime, pot1RedFlag, pot1DelayStartMillis, 
                                POT_1_DRAIN_PERIOD, POT_1_MAX_WATERING_PERIOD,
                                pot1StartMillis, POT_1_FLOAT_SENSOR, POT_1_RELAY_1);

  checkAbstractWateringTimer(pipe1SetStartTime, pipe1RedFlag, pipe1DelayStartMillis, 
                                PIPE_1_DRAIN_PERIOD, PIPE_1_MAX_WATERING_PERIOD,
                                pipe1StartMillis, PIPE_1_FLOAT_SENSOR, PIPE_1_RELAY_1);

  checkAbstractWateringTimer(pipe2SetStartTime, pipe2RedFlag, pipe2DelayStartMillis, 
                                PIPE_2_DRAIN_PERIOD, PIPE_2_MAX_WATERING_PERIOD,
                                pipe2StartMillis, PIPE_2_FLOAT_SENSOR, PIPE_2_RELAY_2);

   checkAbstractWateringTimer(pipe3SetStartTime, pipe3RedFlag, pipe3DelayStartMillis, 
                                PIPE_3_DRAIN_PERIOD, PIPE_3_MAX_WATERING_PERIOD,
                                pipe3StartMillis, PIPE_3_FLOAT_SENSOR, PIPE_3_RELAY_3);

  delay(200);
}

void checkAbstractWateringTimer(bool &abstractSetStartTime, bool &abstractRedFlag, unsigned long &abstractDelayStartMillis, 
                                unsigned long abstractDrainPeriod, unsigned long abstractMaxWateringPeriod,
                                unsigned long &abstractStartMillis, int abstractFloatSensor, int abstractRelay) {
  if (!abstractSetStartTime || (abstractSetStartTime && millis() - abstractDelayStartMillis >= abstractDrainPeriod)) {
    
    if(digitalRead(abstractFloatSensor) == LOW && !abstractRedFlag) // Need one more condition in order to emulate the delay...
    {    
      digitalWrite(abstractRelay, LOW);
      Serial.println("Pot 1 pump is open");
  
      // Set it only once at the beginning
      if (pot1SetStartTime) {
        abstractStartMillis = millis();
        abstractSetStartTime = false;
      }
      
      Serial.print("duration ");
      Serial.println(millis() - abstractStartMillis);
  
      if (millis() - abstractStartMillis >= abstractMaxWateringPeriod)  //test whether the MAX watering period has elapsed
      {
        // Close pump and do not oopen it again. Red Flag...      
        Serial.println("Pot 1 pump is closed and the red flag is ON");
        digitalWrite(abstractRelay, HIGH);
        abstractRedFlag = true;
      }
    } 
    else 
    {
      Serial.println("Pot 1 Pump is closed");
      digitalWrite(abstractRelay, HIGH);
      abstractSetStartTime = true;
      abstractDelayStartMillis = millis();
    }    
  }  
}

Please any ideas, suggestions or tests that I could do are more than welcome in order to create a reliable system.
-- UPDATE --
Both when I was using Raspberry and Arduino I haven't included any resistors between the float sensor pins and the ground. Are there any chances that this is related with the instabilities that I experienced?
Maybe I should add a resistor (10K) between the float sensor pin and the ground?
Thank you

user68310: As requested, I've collated my comments into an answer.
How long are the cable runs? Is there any electrically noisy equipment near the cable runs? Consider using some form of galvanic isolation to interface the float sensors to the MCU. Texas Instruments has a great series of videos on the subject of galvanic isolation which discusses inductive, capacitive and optical isolation techniques. Isolate the signals in both directions – both the inputs and the outputs.
For stronger pull-ups you could try 1K resistors, though this will use more current.
Something else to consider is debouncing the float sensor signals either in hardware with a low-pass RC filter or with a software debouncer (which I've put on GitHub).
The relays require 50 to 60 mA drive current but the Arduino pins can only supply 40 mA, so the external power supply is a good idea.
Redundancy, i.e. having multiple sensors for the same measurement, will guard against the loss of a single sensor causing chaos in a critical system, e.g. loss of precious water in a hot climate. You could have 3 float sensors for each water level at different locations, then use a voting system of >= 2 to take action. The system should also flag when sensors disagree so that someone can investigate the issue. And also route the cables via 3 different paths. This physical separation will guard against a single localised event (e.g. a wayward tractor or lightning strike) damaging all the sensors at the same time.
Also consider the fail-safe mode. For example, this could be to switch off all water valves when sensors disagree and then send an alert to someone and/or sound an alarm.
As your aquaponic farm is outside, consider lightning strike protection such as using TVS diodes on all inputs and outputs.
You could add feedback sensors to the relays to verify whether they have actually responded to the commands from the Arduino to switch on or off, i.e. compare commanded value with FB sensor value. These sensors could be pullup/pulldown resistors.
These additional relay FB sensors and the float sensors could be incorporated into the fail-safe logic. Some examples include:

If a relay is on when it's supposed to be off, flag the discrepancy.
If it takes 5 minutes to fill a tank and the inlet relay has been on for >5 minutes, it might be overflowing or dodgy sensors.
If the float sensors say a tank is empty, but the inlet relay has been on for >5 mins, something is wrong, e.g. leaking tank or dodgy sensors.
If it takes 10 mins to drain a tank but the float sensors say it's still full after 11 mins, something is wrong, e.g. blocked drain or dodgy sensors.
Are inlet and outlet relays on at the same time? Is this a valid condition?

There are many permutations. Happy coding...

77279: <p>I am experimenting with Aquaponics and since I am a software developer I found it &quot;smart&quot; to use arduino/raspberry in order to control the water flow and not simply use a water pump with mechanical means.</p>
<p>The advantage is that I am able to expand easier the system. The disadvantage is that I haven't yet met the reliability that I would lie to have.
I am a software engineer with basic knowledge in the hardware field. That is why I thought of starting with Raspberry.</p>
<p>Initially I made a setup with a single raspberry PI a few float sensors like this: <a href="https://www.hellasdigital.gr/electronics/sensors/humidity-sensor/tank-pool-water-level-liquid-sensor-float-switch/" rel="nofollow noreferrer">https://www.hellasdigital.gr/electronics/sensors/humidity-sensor/tank-pool-water-level-liquid-sensor-float-switch/</a></p>
<p>and relay like this one: <a href="https://wiki.52pi.com/index.php/DockerPi_4_Channel_Relay_SKU:_EP-0099" rel="nofollow noreferrer">https://wiki.52pi.com/index.php/DockerPi_4_Channel_Relay_SKU:_EP-0099</a></p>
<p>I saw that sometimes the system was hanging with the relays open! This had the side effect to loose water. This is the most precious in aquaponics!</p>
<p>Thus I thought of creating a cluster. Thus I made a cluster of three Raspberrys. The two had the relays and only one PI had the sensors. In order to open the water pump both PIs should have given the green light. This worked better and when one of the PIs hanged then we lost no water.</p>
<p>But again I am thinking that it was not acceptable that the system was hanging so often (at least several times per week). Thus I thought maybe if I use an Arduino for this purpose then this would be better.</p>
<p>Thus this is what I did. I created a simple program (no cluster and a single Arduino). Unfortunately this had even worst results!!!</p>
<p>For the Arduino I used normal 5 Volt relays like this one: <a href="https://www.nettop.gr/index.php/hlektronika/relay/8-channel-5v-relay-module-with-light-coupling-5v.html" rel="nofollow noreferrer">https://www.nettop.gr/index.php/hlektronika/relay/8-channel-5v-relay-module-with-light-coupling-5v.html</a> and the same float sensors.</p>
<p>I do not believe that is software related the issue but it must be hardware.
The problem is that my knowledge in the hardware field is limited!
What should I do in order to prevent this? Do you think that is related with the water pumps and the relays ?</p>
<p>The same erroneous behavior happens at both the Raspberry and Arduino, I mean that the relay stays open and the water overflows. For Raspberry I can tell that the system stop to respond, I am sure about it. But for Arduino I cannot say for sure if the whole system was frozen or if input only for the float did not work.</p>
<p>I paste a link to the quick and dirty Arduino code as well for your reference.
The temperature were the systems were operating could be quite hot (30 ~ 48 degrees Celsius) for several hours.</p>
<p>Here is the code for the Arduino:</p>
<pre class="lang-cpp prettyprint-override"><code>#define POT_1_FLOAT_SENSOR  2 
#define POT_1_RELAY_1       11     

#define PIPE_1_FLOAT_SENSOR  5 
#define PIPE_1_RELAY_1       9     

#define PIPE_2_FLOAT_SENSOR       3     
#define PIPE_2_RELAY_2      10     

#define PIPE_3_RELAY_3       12    
#define PIPE_3_FLOAT_SENSOR       4     

// pot 1
const unsigned long POT_1_MAX_WATERING_PERIOD = 120000;
const unsigned long POT_1_DRAIN_PERIOD = 70000;

unsigned long pot1StartMillis = 0;
unsigned long pot1DelayStartMillis = 0;

// Pipe 2
const unsigned long PIPE_2_MAX_WATERING_PERIOD = 300000;
const unsigned long PIPE_2_DRAIN_PERIOD = 300000;

unsigned long pipe2DelayStartMillis = 0;
unsigned long pipe2StartMillis = 0;

// Pipe 3
const unsigned long PIPE_3_MAX_WATERING_PERIOD = 760000;
const unsigned long PIPE_3_DRAIN_PERIOD = 300000;
unsigned long pipe3DelayStartMillis = 0;
unsigned long pipe3StartMillis = 0;

// Pipe 1
const unsigned long PIPE_1_MAX_WATERING_PERIOD = 180000;
const unsigned long PIPE_1_DRAIN_PERIOD = 300000;
unsigned long pipe1DelayStartMillis = 0;
unsigned long pipe1StartMillis = 0;



bool pot1RedFlag = false;
bool pot1SetStartTime = false;

bool pipe1RedFlag = false;
bool pipe1SetStartTime = false;

bool pipe2RedFlag = false;
bool pipe2SetStartTime = false;

bool pipe3RedFlag = false;
bool pipe3SetStartTime = false;



void setup() 
{
  Serial.begin(9600);
  // initialize the pushbutton pin as an input:
  pinMode(POT_1_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(POT_1_RELAY_1, OUTPUT);
  digitalWrite(POT_1_RELAY_1, LOW);

  pinMode(PIPE_1_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_1_RELAY_1, OUTPUT);
  digitalWrite(PIPE_1_RELAY_1, LOW);

  pinMode(PIPE_2_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_2_RELAY_2, OUTPUT);
  digitalWrite(PIPE_2_RELAY_2, LOW);

  pinMode(PIPE_3_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_3_RELAY_3, OUTPUT);
  digitalWrite(PIPE_3_RELAY_3, LOW);
  
  pot1StartMillis = millis();
  pipe1StartMillis = millis();
  pipe2StartMillis = millis();
  pipe3StartMillis = millis();
}

void loop() 
{
  checkAbstractWateringTimer(pot1SetStartTime, pot1RedFlag, pot1DelayStartMillis, 
                                POT_1_DRAIN_PERIOD, POT_1_MAX_WATERING_PERIOD,
                                pot1StartMillis, POT_1_FLOAT_SENSOR, POT_1_RELAY_1);

  checkAbstractWateringTimer(pipe1SetStartTime, pipe1RedFlag, pipe1DelayStartMillis, 
                                PIPE_1_DRAIN_PERIOD, PIPE_1_MAX_WATERING_PERIOD,
                                pipe1StartMillis, PIPE_1_FLOAT_SENSOR, PIPE_1_RELAY_1);

  checkAbstractWateringTimer(pipe2SetStartTime, pipe2RedFlag, pipe2DelayStartMillis, 
                                PIPE_2_DRAIN_PERIOD, PIPE_2_MAX_WATERING_PERIOD,
                                pipe2StartMillis, PIPE_2_FLOAT_SENSOR, PIPE_2_RELAY_2);

   checkAbstractWateringTimer(pipe3SetStartTime, pipe3RedFlag, pipe3DelayStartMillis, 
                                PIPE_3_DRAIN_PERIOD, PIPE_3_MAX_WATERING_PERIOD,
                                pipe3StartMillis, PIPE_3_FLOAT_SENSOR, PIPE_3_RELAY_3);

  delay(200);
}

void checkAbstractWateringTimer(bool &amp;abstractSetStartTime, bool &amp;abstractRedFlag, unsigned long &amp;abstractDelayStartMillis, 
                                unsigned long abstractDrainPeriod, unsigned long abstractMaxWateringPeriod,
                                unsigned long &amp;abstractStartMillis, int abstractFloatSensor, int abstractRelay) {
  if (!abstractSetStartTime || (abstractSetStartTime &amp;&amp; millis() - abstractDelayStartMillis &gt;= abstractDrainPeriod)) {
    
    if(digitalRead(abstractFloatSensor) == LOW &amp;&amp; !abstractRedFlag) // Need one more condition in order to emulate the delay...
    {    
      digitalWrite(abstractRelay, LOW);
      Serial.println(&quot;Pot 1 pump is open&quot;);
  
      // Set it only once at the beginning
      if (pot1SetStartTime) {
        abstractStartMillis = millis();
        abstractSetStartTime = false;
      }
      
      Serial.print(&quot;duration &quot;);
      Serial.println(millis() - abstractStartMillis);
  
      if (millis() - abstractStartMillis &gt;= abstractMaxWateringPeriod)  //test whether the MAX watering period has elapsed
      {
        // Close pump and do not oopen it again. Red Flag...      
        Serial.println(&quot;Pot 1 pump is closed and the red flag is ON&quot;);
        digitalWrite(abstractRelay, HIGH);
        abstractRedFlag = true;
      }
    } 
    else 
    {
      Serial.println(&quot;Pot 1 Pump is closed&quot;);
      digitalWrite(abstractRelay, HIGH);
      abstractSetStartTime = true;
      abstractDelayStartMillis = millis();
    }    
  }  
}
</code></pre>
<p>Please any ideas, suggestions or tests that I could do are more than welcome in order to create a reliable system.</p>
<p>-- UPDATE --
Both when I was using Raspberry and Arduino I haven't included any resistors between the float sensor pins and the ground. Are there any chances that this is related with the instabilities that I experienced?</p>
<p>Maybe I should add a resistor (10K) between the float sensor pin and the ground?</p>
<p>Thank you</p>
 68310: <p>As requested, I've collated my comments into an answer.</p>
<p>How long are the cable runs? Is there any electrically noisy equipment near the cable runs? Consider using some form of galvanic isolation to interface the float sensors to the MCU. Texas Instruments has a great series of videos on the subject of <a href="https://training.ti.com/ti-precision-labs-isolation-what-galvanic-isolation" rel="nofollow noreferrer">galvanic isolation</a> which discusses inductive, capacitive and optical isolation techniques. Isolate the signals in both directions – both the inputs and the outputs.</p>
<p>For stronger pull-ups you could try 1K resistors, though this will use more current.</p>
<p>Something else to consider is debouncing the float sensor signals either in hardware with a low-pass RC filter or with a <a href="https://github.com/TimMathias/Arduino-Debouncer" rel="nofollow noreferrer">software debouncer</a> (which I've put on GitHub).</p>
<p>The relays require 50 to 60 mA drive current but the Arduino pins can only supply 40 mA, so the external power supply is a good idea.</p>
<p>Redundancy, i.e. having multiple sensors for the same measurement, will guard against the loss of a single sensor causing chaos in a critical system, e.g. loss of precious water in a hot climate. You could have 3 float sensors for each water level at different locations, then use a voting system of &gt;= 2 to take action. The system should also flag when sensors disagree so that someone can investigate the issue. And also route the cables via 3 different paths. This physical separation will guard against a single localised event (e.g. a wayward tractor or lightning strike) damaging all the sensors at the same time.</p>
<p>Also consider the fail-safe mode. For example, this could be to switch off all water valves when sensors disagree and then send an alert to someone and/or sound an alarm.</p>
<p>As your aquaponic farm is outside, consider lightning strike protection such as using TVS diodes on all inputs and outputs.</p>
<p>You could add feedback sensors to the relays to verify whether they have actually responded to the commands from the Arduino to switch on or off, i.e. compare commanded value with FB sensor value. These sensors could be pullup/pulldown resistors.</p>
<p>These additional relay FB sensors and the float sensors could be incorporated into the fail-safe logic. Some examples include:</p>
<ol>
<li>If a relay is on when it's supposed to be off, flag the discrepancy.</li>
<li>If it takes 5 minutes to fill a tank and the inlet relay has been on for &gt;5 minutes, it might be overflowing or dodgy sensors.</li>
<li>If the float sensors say a tank is empty, but the inlet relay has been on for &gt;5 mins, something is wrong, e.g. leaking tank or dodgy sensors.</li>
<li>If it takes 10 mins to drain a tank but the float sensors say it's still full after 11 mins, something is wrong, e.g. blocked drain or dodgy sensors.</li>
<li>Are inlet and outlet relays on at the same time? Is this a valid condition?</li>
</ol>
<p>There are many permutations. Happy coding...</p>
