As the functions that you presented are not called yet, it's a bit difficult to determine if you're on the right track. Your code is currently lacking a timing for the drain and timing is part of the 'states' that you can have. This will make your 'bunch of' if statements in checkStates more complicated and possibly nobody might be able to follow it; even you might get lost if you look at your code in a year's time to do a modification (it happens to me ;))
As I see it, you can have three states
- STOPPED: all valves are closed
- DRAINING: the drain and fill valves are open
- FILLING: only the fill valves are open
You can have a fourth one indicating STARTDRAIN if you want to
Let's assume you use the three above. Your flow would be
Stopped -(A)-> Draining -(B)-> Filling
^ |
| |
+-------------(C)--------------+
(A), (B) and (C) represent the conditions for a change in state.
(A) will be if the code detects that one of the tanks is empty.
(B) will be if the code detects that the drain period has lapsed
(C) will be if the code detects that both tanks are full
You can write a few functions that are executed when a certain stage is reached.
Functions I see are
- checkTankEmpty() that will check if one of the tanks is empty and if so, calls the below drain() function to start the drain process.
- drain() that will open the valves responsible for draining and change the state from STOPPED to DRAINING. It will also check the progress (duration) of the drain process; once the drain process is finished, the drain() function will close the drain valve and open the relevant output valves and it will change the state from DRAINING to FILLING.
- fill() that will close the relevant valve if it detects that a tank is full and it will change the state from FILLING to STOPPED if it detects that both tanks are full.
The below shows the relevant constants and variable for the state machine
// States
#define STOPPED 0 //
#define DRAINING 1 // filling and draining
#define FILLING 2 // filling only
// current state of statemachine; initial value stopped
byte state = STOPPED;
The below can be an example for the loop() function
void loop()
{
checkSensors();
switch (state)
{
case STOPPED:
// check if one or more tanks are empty
checkTankEmpty();
break;
case DRAINING:
// continue draining
drain();
break;
case FILLING:
// stop draining, continue filling
fill();
break;
}
}
Example of checkTankEmpty()
void checkTankEmpty()
{
// check if one of the tanks is empty
if (status.t1Low == TANKEMPTY || status.t2Low == TANKEMPTY)
{
// start draining; the drain function will change the state so we do not do it here
drain();
}
}
The framework for the drain() function
void drain()
{
if(starttime == 0)
{
start time = current time
open valves required for draining
state = DRAINING;
}
else
{
if(current time - start time > drain duration)
{
close drain valve
open relevant output valves
start time = 0
state = FILLING
}
else
{
// should not get here
}
}
}
And for the fill() function
void fill()
{
if (tank 1 == full)
close relevant output valve
if (tank 2 == full)
close relevant output valve
if (tank 1 == full && tank 2 == full)
{
close input valve
state = STOPPED
}
}
The only point that is not taken into account in the fill function is that while one tank is still filling and the other one already had reached 'full', the 'full' of the latter might no longer be valid when the former one reaches 'full' and hence the condition that tests both might not evaluate to true. You can solve it with some additional variables.
Note:
You can maybe extend your table in post #6 (for your own purposes and if you post it (not update) for our understanding of your code) to indicate which valves should be open for each condition.