// https://forum.arduino.cc/t/two-slide-switches-to-sequence-leds/1012696
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
# define PIXEL_PIN 6
# define NLAMPS 20 // tank display size
Adafruit_NeoPixel tank(NLAMPS, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// tank model stuff
# define FULL_TANK ((NLAMPS - 1) * 32 + 31) // mixed point tank level
# define TANK_FILL_RATE A0 // analog input for tank fill rate
# define FILL_ON A1 // switch controls filling of tank
# define UPPER_FLOAT 5 // outputs from level sensors - use as inputs to logic
# define LOWER_FLOAT 4
// pump stuff
# define NPUMPS 2
unsigned char pumpState[NPUMPS] = {0, 0};
const unsigned char pumpRelay[NPUMPS] = {8, 7}; // pump relays
const unsigned char pumpButton[NPUMPS] = {3, 2}; // pump manual controls
void setup() {
Serial.begin(115200);
Serial.println("Hello Tank World!\n");
tank.begin(); // neopixel
pinMode(FILL_ON, INPUT_PULLUP);
pinMode(UPPER_FLOAT, OUTPUT);
pinMode(LOWER_FLOAT, OUTPUT);
for (unsigned char ix = 0; ix < NPUMPS; ix++) {
pinMode(pumpButton[ix], INPUT_PULLUP);
pinMode(pumpRelay[ix], OUTPUT);
digitalWrite(pumpRelay[ix], LOW);
}
tank.show();
setupOP(); // run OP's setup function
}
void loop()
{
// run the model tank and pumps thing
tankPumpWorld();
printStatus();
// below here you have full speed loop
// here we just defer to the OP's logic:
loopOP();
}
// handle tank and pump simulation.
int tankLevel;
void tankPumpWorld() {
static unsigned long lastLoop;
unsigned long now = millis(); //grab current time
if (now - lastLoop < 50) return; // 20 Hz all around
lastLoop = now;
// tank simulation and manual controls
// flawed checkPumpSwitches();
tankSimulate(); // update the tank model
displayTank();
}
// system status report
void printStatus()
{
static unsigned long lastReport;
unsigned long now = millis();
if (now - lastReport < 1333) return;
lastReport = now;
unsigned char tankFull = digitalRead(UPPER_FLOAT); // just read the status lamp!
unsigned char tankEmpty = !digitalRead(LOWER_FLOAT); // just read the status lamp!
if (tankFull) Serial.print("tank is full ");
if (tankEmpty) Serial.print("tank is empty ");
if (pumpState[0]) Serial.print("pump one is ON ");
if (pumpState[1]) Serial.print("pump two is ON ");
if (!digitalRead(FILL_ON)) {
Serial.print(" the tank is filling at ");
Serial.print((analogRead(TANK_FILL_RATE) >> 6) + 1);
Serial.print(" units per tick.");
}
else Serial.print(" the fill valve is closed.");
Serial.print(" tank level "); Serial.println(tankLevel);
}
// fill and empty the tank.
void tankSimulate()
{
int rate = (analogRead(TANK_FILL_RATE) >> 6) + 1;
// Serial.println(rate); 1 to 16 units per tick, fine
if (digitalRead(FILL_ON) == LOW)
addToTank(rate);
runPumps();
}
void displayTank()
{
int tankI = tankLevel >> 5;
for (unsigned char ix = 0; ix < NLAMPS; ix++) tank.setPixelColor(ix, 0);
if (tankLevel)
for (unsigned char ix = 0; ix <= tankI; ix++) tank.setPixelColor(ix, 0x0000ff);
digitalWrite(UPPER_FLOAT, tankLevel >= FULL_TANK);
digitalWrite(LOWER_FLOAT, tankLevel > 0 ? HIGH : LOW);
tank.show();
}
// turn a pump on or off - logic
void switchPump(unsigned char thePump, unsigned char onOff)
{
pumpState[thePump] = onOff;
}
// get sgtate of pump running/not running
unsigned char pumpIsOn(unsigned char thePump)
{
return pumpState[thePump];
}
// turn off or on the pumps - mechanical. subtract from tank.
// heed the pushbutton manual pump control!
// pump control of OP inverted, took care
void runPumps()
{
for (unsigned char ix = 0; ix < NPUMPS; ix++)
if (pumpState[ix] || digitalRead(pumpButton[ix])) {
digitalWrite(pumpRelay[ix], HIGH);
addToTank(-5);
}
else digitalWrite(pumpRelay[ix], LOW);
}
// add or subtract from the tank. limit 0..full
void addToTank(int units)
{
tankLevel += units;
if (tankLevel > FULL_TANK) tankLevel = FULL_TANK;
if (tankLevel < 0) tankLevel = 0;
}
// below is the OP's solution only slightly adjusted to fit with the tank simulator
/*
const int pump_1 = 3;
const int pump_2 = 4;
const int waterLow = 8;
const int waterHigh = 9;
const int alarm = 2;
*/
// listen and talk to the simulation of the tank and pumps:
const int pump_1 = 9;
const int pump_2 = 10; // 9 and 10, pump control. wire where manual switches were
const int waterLow = 11;
const int waterHigh = 12; // 11 and 12, sensor inputs, wire to sensor LEDs
const int alarm = A2;
const unsigned long pumpInterval = 10000; // is this the 30 second test?
const unsigned long alarmInterval = 2000;
unsigned long pumpOnTime;
int lowState = LOW;
int highState = LOW;
int nextState;
int currentState;
//possible states of the state-machine
typedef enum {STATE_IDLE,
STATE_IDLE_2,
STATE_RUN1,
STATE_RUN2,
STATE_RUN3,
STATE_RUN4,
STATE_ALARM,
STATE_ALARM2} states;
void setupOP() {
// Serial.begin(9600); //start serial interface for debugging & monitoring
nextState = STATE_IDLE; // set the initial state of the machine in setup
currentState = nextState; // sets the state of each case
//set pin modes for each pin:
pinMode(pump_1, OUTPUT);
pinMode(pump_2, OUTPUT);
pinMode(alarm, OUTPUT);
pinMode(waterLow, INPUT_PULLUP);
pinMode(waterHigh, INPUT_PULLUP);
}
void loopOP() {
const unsigned long currentTime = millis(); // set current time
int tankFull; //set tank full variable to monitor switches in place of sensors
//read state of each "sensor" and declare states
lowState = digitalRead(waterLow);
highState = digitalRead(waterHigh);
tankFull = lowState + highState; //define tankFull calculation.
//tank full (when lowState = 1 and highState = 1)
// use switch... case to manage pump sequence
switch(currentState){
case STATE_IDLE:
if(tankFull == 2){
Serial.println("tank full");
nextState = STATE_RUN1;
}else if(tankFull == 0){
digitalWrite(pump_1, LOW);
digitalWrite(pump_2, LOW);
digitalWrite(alarm, LOW);
}
break;
case STATE_RUN1:
lowState = digitalRead(waterLow);
highState = digitalRead(waterHigh);
tankFull = lowState + highState;
if(tankFull >= 1){
digitalWrite(pump_1, HIGH);
pumpOnTime = currentTime;
Serial.println("Pump 1 Running");
Serial.println("Pump 1 start time: ");
Serial.print(currentTime);
Serial.println(" ");
// tankCycle++;
nextState = STATE_RUN2;
}else if(tankFull == 0){
digitalWrite(pump_1, LOW);
digitalWrite(pump_2, LOW);
digitalWrite(alarm, LOW);
Serial.println("Tank Empty");
nextState = STATE_IDLE_2;
}
break;
case STATE_RUN2:
lowState = digitalRead(waterLow);
highState = digitalRead(waterHigh);
tankFull = lowState + highState;
if(tankFull >=1){
if(currentTime - pumpOnTime >= pumpInterval){
digitalWrite(pump_2, HIGH);
pumpOnTime = currentTime;
Serial.println("Pump 2 running");
Serial.println("Pump 2 Start Time: ");
Serial.print(pumpOnTime);
Serial.println("");
nextState = STATE_ALARM;
}
}else if(tankFull == 0){
digitalWrite(pump_1, LOW);
digitalWrite(pump_2, LOW);
digitalWrite(alarm, LOW);
Serial.println("Tank Empty");
nextState = STATE_IDLE_2;
}
break;
case STATE_ALARM:
lowState = digitalRead(waterLow);
highState = digitalRead(waterHigh);
tankFull = lowState + highState;
if(tankFull >= 1){
if(currentTime - pumpOnTime >= alarmInterval){
digitalWrite(alarm, HIGH);
Serial.println("Alarm on");
Serial.println("Alarm start time:");
Serial.print(currentTime);
Serial.println("");
nextState = STATE_IDLE_2;
}
}else if(tankFull == 0){
digitalWrite(pump_1, LOW);
digitalWrite(pump_2, LOW);
digitalWrite(alarm, LOW);
Serial.println("Tank Empty");
nextState = STATE_IDLE_2;
}
break;
case STATE_IDLE_2:
if(tankFull == 2){
Serial.println("tank full");
nextState = STATE_RUN3;
}
else if(tankFull == 0){
digitalWrite(pump_1, LOW);
digitalWrite(pump_2, LOW);
digitalWrite(alarm, LOW);
}
break;
case STATE_RUN3:
lowState = digitalRead(waterLow);
highState = digitalRead(waterHigh);
tankFull = lowState + highState;
if(tankFull >= 1){
digitalWrite(pump_2, HIGH);
pumpOnTime = currentTime;
Serial.println("Pump 2 Running");
Serial.println("Pump 2 start time: ");
Serial.print(currentTime);
Serial.println(" ");
nextState = STATE_RUN4;
}else if(tankFull == 0){
digitalWrite(pump_1, LOW);
digitalWrite(pump_2, LOW);
digitalWrite(alarm, LOW);
Serial.println("Tank Empty");
nextState = STATE_IDLE;
}
break;
case STATE_RUN4:
lowState = digitalRead(waterLow);
highState = digitalRead(waterHigh);
tankFull = lowState + highState;
if(tankFull >=1){
if(currentTime - pumpOnTime >= pumpInterval){
digitalWrite(pump_1, HIGH);
pumpOnTime = currentTime;
Serial.println("Pump 1 running");
Serial.println("Pump 1 Start Time: ");
Serial.print(pumpOnTime);
Serial.println("");
nextState = STATE_ALARM2;
}
}else if(tankFull == 0){
digitalWrite(pump_1, LOW);
digitalWrite(pump_2, LOW);
digitalWrite(alarm, LOW);
Serial.println("Tank Empty");
nextState = STATE_IDLE;
}
break;
case STATE_ALARM2:
lowState = digitalRead(waterLow);
highState = digitalRead(waterHigh);
tankFull = lowState + highState;
if(tankFull >= 1){
if(currentTime - pumpOnTime >= alarmInterval){
digitalWrite(alarm, HIGH);
Serial.println("Alarm on");
Serial.println("Alarm start time:");
Serial.print(currentTime);
Serial.println("");
nextState = STATE_IDLE;
}
}else if(tankFull == 0){
digitalWrite(pump_1, LOW);
digitalWrite(pump_2, LOW);
digitalWrite(alarm, LOW);
Serial.println("Tank Empty");
nextState = STATE_IDLE;
}
break;
}
currentState = nextState;
}