/*
Timed Auto Level Controller with motor (via relay) start stop
Adjust levels of a unit by using times in an Array to switch up
or down to the desired level.
Switch a relay on or off based on Time array
Switch a puff motor on or off based on a different array.
Switch motor on a set period of time before desired to build up pressure
Open a solenoid valve for set time after the motor has started
then Close the solenoid valve
Future motor and solenoid remote- send switch on via ESPnow
V1 Basics
20240815 Initial setup, test leds, switch push function
Compare (random)new level to current level and send to correct
switch up or down function
20240815 Get difference between new level and current level, switch led (future switches)
correct number of times up or down to change current level to new level
Loop watching for button press before continuing
Send VLC start (currently to LED)
Compare and Switch levels in own functions
V2 Add Arrays
Option1
at first event trigger set level and activate relay
relay stays closed and levels change and event triggers
20240816 Stopping at runtime end - maybe able to do better than a runtime variable
(Add into Array?)
20240819
Option2
Relay closes at event time trigger and reopens after set time
relay on time + duration (relay switch off time) > timenow switch off relay
Create time to switch off relay when switching relay on
20240820
Add airpump array
Add duration of pump running
20240822
Add end function after stop function to prevent stack overflow
20240826
Add LEds for Magnet Lock and solenoid valve
(to be sent via ESPNow)
Add AirValve Array
20240910
Try to get arrays from over running and loading another memory space
add
if(doPump < numberofPumpTriggers && !PumpArrayComplete)
{
if (Array index == Array length){Array Complete} //inside relay event
}
20240911
Add option for relay always on - works
Add random mode option for device
chooses one mode for duration
*/
//Future includes
//wifi for espnow
// ble or serial for sending VLC
//define pins
//Outputs
//Leds used to show switch ouptuts
#define Up_SwitchPin 17 //Use p4 on board
#define Dwn_SwitchPin 5 //Use p16 on board
#define RelayPin 4 //Use p23 on board
#define ModePin 0 //Use p0 on board
//send via ESPnow in future
#define PumpPwr 16 //for testing of array. future use espnow
#define airValve 19 //airValve
#define Magnet 21//Magnet
//send via BLE (via attached micro digital pin or serial)
#define VLC_BLE 18 //for testing. Send Bluetooth to device or use
// as input to another device for sending BLE
//Inputs
#define Startswitch 33 // use P15 on board
//States
boolean SwitchState;
boolean Started = false;
boolean Running = false;
bool DeviceOn = false;
boolean Stopped = false;
boolean VLCStopped = false;
bool EventArrayComplete = false;
bool PumpArrayComplete = false;
bool RelayState = false;
bool PumpPwrState = false;
bool airValvePwrState = false;
// Define time variables
unsigned long TimerStarted;
unsigned long Timenow;
unsigned long OnTime;
unsigned long TimeRemaining; // used in testing
unsigned long RelaySwitchOffTime;
unsigned long PumpSwitchOffTime;
unsigned long StopVLCTime;
//
int StartLevel = 0;
int CurrentLevel = StartLevel;
int NewLevel;
int CurrentMode = 1;
int NewMode;
int SwitchDelay = 100; //ms between toggling switch (leds in sim) on and off
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//Play Device variables set before starting
//USER INPUTS :future input through webpage or config file
unsigned long runTime_seconds = 35;
bool RelayAlwaysOn = false; //use true when relay always on
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
unsigned long runTime = runTime_seconds * 1000; // run time converted to milliseconds
//
//*******ARRAYS**********************************
//SETUP ARRAYS HERE
// Switch Device Time Arrays
// Must have equal number of entries
const int numberofEventTriggers = 6; //number of sequence steps
int doTrigger = 0; //initialise starting point of sequence array
unsigned long EventTime[numberofEventTriggers] = {3, 8, 13, 18, 22, 28}; //array of time events in seconds
unsigned long durationTime[numberofEventTriggers] = {2000, 2500, 2500, 2000, 2500, 2000}; //in ms, array of duration of doing something
int EventLevel[numberofEventTriggers] = {3 ,10, 5, 10, 7, 10}; //level to action at, number of actions same for all sequences
//initialise Arrays
int performEvent = EventTime[doTrigger]; // which time event to action
unsigned long performEvent_ms = performEvent * 1000 ; //convert time event to milliseconds
unsigned long durationAction = durationTime[doTrigger]; // which duration event to action, matched to a time event
int doLevels = 0; //set start level
int performLevel = EventLevel[doTrigger];
// Air pump arrays
const int numberofPumpTriggers = 6; //number of sequence steps
int doPump = 0; //initialise starting point of sequence array
unsigned long PumpSwitchOn[numberofPumpTriggers] = {3, 8, 13, 18, 22, 28}; //array of time events in seconds
unsigned long PumpdurationTime[numberofPumpTriggers] = {2000, 2500, 2500, 2000, 2500, 2000}; //in ms, array of duration of doing something
//initialise pump Arrays
int PumpOnEvent = PumpSwitchOn[doPump]; // which time event to action
unsigned long PumpOnEvent_ms = PumpOnEvent * 1000 ; //convert time event to milliseconds
unsigned long durationPump = PumpdurationTime[doPump]; // which duration event to action, matched to a time event
//Air Solenoid Valve Arrays
//Same number of triggers as pump on. Valve only opens when pump running. Closes at same time
unsigned long airValveOn[numberofPumpTriggers] = {3, 8, 13, 18, 22, 28}; //array of time events in seconds
//initialise valve Arrays
int airValveOnEvent = airValveOn[doPump]; // which time event to action
unsigned long airValveOnEvent_ms = airValveOnEvent * 1000 ; //convert time event to milliseconds
// Random Mode
const int numberofModes = 8;
int Mode_Array[numberofModes] = {1, 2, 3, 4, 5, 6, 7, 8}; //array of time events in seconds
int random_Mode = random(0,(numberofModes-1));
int choose_Mode = Mode_Array[random_Mode]; // Choose mode to use
int Mode ;
//**********************************************
void setup() {
//Initialise pins
pinMode(ModePin, OUTPUT);
digitalWrite(ModePin, LOW);
pinMode(Up_SwitchPin, OUTPUT);
digitalWrite(Up_SwitchPin, LOW);
pinMode(Dwn_SwitchPin, OUTPUT);
digitalWrite(Dwn_SwitchPin, LOW);
pinMode(RelayPin, OUTPUT);
digitalWrite(RelayPin, LOW);
pinMode(PumpPwr, OUTPUT);
digitalWrite(PumpPwr, LOW);
pinMode(VLC_BLE, OUTPUT);
digitalWrite(VLC_BLE, LOW);
pinMode(airValve, OUTPUT);
digitalWrite(airValve, LOW);
pinMode(Magnet, OUTPUT);
digitalWrite(Magnet, LOW);
pinMode(Startswitch, INPUT);
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32!");
//power up indication for testing only remove later
digitalWrite(ModePin, HIGH);
digitalWrite(Dwn_SwitchPin, HIGH);
digitalWrite(Up_SwitchPin, HIGH);
digitalWrite(RelayPin, HIGH);
digitalWrite(VLC_BLE, HIGH);
digitalWrite(PumpPwr, HIGH); //future send to motor via espnow
digitalWrite(airValve, HIGH);
digitalWrite(Magnet, HIGH);
delay(250);
digitalWrite(ModePin, LOW);
digitalWrite(Dwn_SwitchPin, LOW);
digitalWrite(Up_SwitchPin, LOW);
digitalWrite(RelayPin, LOW);
digitalWrite(VLC_BLE, LOW);
digitalWrite(PumpPwr, LOW); //future send to motor via espnow
digitalWrite(airValve, LOW);
digitalWrite(Magnet, LOW);
// give array starting value
NewLevel= performLevel;
}
void loop() {
if (Stopped){End();} //test if stopped before any other code runs
Serial.println(" ");
Serial.println("************ ");
//NewMode = choose_Mode;
Serial.println(NewMode);
/*
Serial.print("runTime: ");Serial.println(runTime);
Serial.print("RelayOn_ms: ");Serial.println(performEvent_ms);
Serial.print("RelaySwitchOffTime: ");Serial.println(RelaySwitchOffTime);
Serial.print("NewLevel: ");Serial.println(NewLevel);
Serial.print("CurrentLevel: ");Serial.println(CurrentLevel);
Serial.print("RelayArray position: ");Serial.println(doTrigger);
Serial.print("PumpOnEvent_ms: ");Serial.println(PumpOnEvent_ms);
Serial.print("durationPump: ");Serial.println(durationPump);
Serial.print("PumpArray position: ");Serial.println(doPump);
*/
//testing switch
SwitchState = digitalRead(Startswitch);
Serial.print("SwitchState: ");Serial.println(SwitchState);
//testing if loop
if (!SwitchState && !Started)
{
// if button pressed change state to started and running
Started = true;
Running = false;
Stopped = false;
TimerStarted = millis();
digitalWrite(Magnet, HIGH);
//PUT DELAY HERE BEFORE STARTING VLC
// void delayStart(){}
}
if (Started && !Running)
{
OnTime = millis();
// button has been pressed state started is true and running
//start VLC BLE
Start_VLC();
}
//runningstate started is true
if (Running)
{
Serial.println("");
Serial.print("Event RUNNING: "); Serial.println(Running) ;
Started = false; //next state is running. Started no longer true
Timenow = (millis()- OnTime);
Serial.print("Timenow: ");Serial.println(Timenow);
//Compare Array time to Time now. If in range do change level
if (Timenow >= runTime)
{
StopVLCTime = millis();
Stop();
return;
} // Stop if time up
if (Timenow >= RelaySwitchOffTime && !RelayAlwaysOn ){RelayOff();} // Switch relay off if time up
if (Timenow >= PumpSwitchOffTime && PumpPwrState){PumpOff();} // Switch relay off if time up
if ((Timenow >= performEvent_ms) )
{
if(!DeviceOn)
{
RelayEvent();
ModeCheck();
DeviceOn = true;
}
if(DeviceOn)
{
ModeCheck();
RelayEvent();
}
}
if ((Timenow >= PumpOnEvent_ms) && !PumpPwrState )
{ PumpEvent(); }
if ((Timenow >= airValveOnEvent_ms) && !airValvePwrState )
{ airValveEvent(); }
}
//
delay(10); // this speeds up the simulation
} //loop end
void ModeCheck()
{
//compare modes
Serial.println("Mode check");
if (CurrentMode > NewMode){ModeDown();}
if (CurrentMode < NewMode){ModeUp();}
random_Mode = random(0,(numberofModes-1));
choose_Mode = Mode_Array[random_Mode]; // Choose mode to use
NewMode = choose_Mode;
} //end Mode check
void ModeUp()
{
Serial.print("CurrenModeUP Loop: ");Serial.println(CurrentMode);
int StepLevel = (NewMode - CurrentMode );
Serial.print("steps to New Mode= ") ; Serial.println(StepLevel) ;
for (int i = 0; i < StepLevel ; i++ )
{
digitalWrite(ModePin, HIGH);
delay(SwitchDelay);
digitalWrite(ModePin, LOW);
delay(SwitchDelay);
Serial.print("i UPloop= ") ; Serial.println(i) ;
CurrentMode = NewMode;
Serial.print("NEW_currentMode= ") ; Serial.println(CurrentMode) ;
} //for loop
} //modeup function
void ModeDown()
{
Serial.print("CurrentModeDwn Loop: ");Serial.println(CurrentMode);
int StepLevel = ( CurrentMode - NewMode );
Serial.print("steps to New Mode= ") ; Serial.println(StepLevel) ;
for (int i = 0; i < StepLevel ; i++ )
{
digitalWrite(ModePin, HIGH);
delay(SwitchDelay);
digitalWrite(ModePin, LOW);
delay(SwitchDelay);
Serial.print("i DWNloop= ") ; Serial.println(i) ;
CurrentMode = NewMode;
Serial.print("NEW_currentMode= ") ; Serial.println(CurrentMode) ;
} //for loop
} //end mode dwn function
void LevelCheck()
{
//compare levels
Serial.println("level check");
if (CurrentLevel > NewLevel){LevelDown();}
if (CurrentLevel < NewLevel){LevelUp();}
}
void LevelUp()
{
Serial.print("CurrentLevelUP Loop: ");Serial.println(CurrentLevel);
int StepLevel = (NewLevel - CurrentLevel );
Serial.print("steps to New Level= ") ; Serial.println(StepLevel) ;
for (int i = 0; i < StepLevel ; i++ )
{
digitalWrite(Up_SwitchPin, HIGH);
delay(SwitchDelay);
digitalWrite(Up_SwitchPin, LOW);
delay(SwitchDelay);
Serial.print("i UPloop= ") ; Serial.println(i) ;
CurrentLevel = NewLevel;
Serial.print("NEW_currentLevel= ") ; Serial.println(CurrentLevel) ;
} //for loop
} //level up function
void LevelDown()
{
Serial.print("CurrentLevelDwn Loop: ");Serial.println(CurrentLevel);
int StepLevel = ( CurrentLevel - NewLevel );
Serial.print("steps to New Level= ") ; Serial.println(StepLevel) ;
for (int i = 0; i < StepLevel ; i++ )
{
digitalWrite(Dwn_SwitchPin, HIGH);
delay(SwitchDelay);
digitalWrite(Dwn_SwitchPin, LOW);
delay(SwitchDelay);
Serial.print("i DWNloop= ") ; Serial.println(i) ;
CurrentLevel = NewLevel;
Serial.print("NEW_currentLevel= ") ; Serial.println(CurrentLevel) ;
} //for loop
} //level dwn function
void Start_VLC()
{
unsigned long BLE_delay = 500;
digitalWrite(VLC_BLE, HIGH);
if (millis()- TimerStarted >= BLE_delay)
{
digitalWrite(VLC_BLE, LOW);
Running = true;
return;
}
} //start vlc
void Stop_VLC()
{
if (VLCStopped){Stop();}
unsigned long BLE_delay = 1000;
digitalWrite(VLC_BLE, HIGH);
if ((StopVLCTime - runTime) >= BLE_delay)
{
digitalWrite(VLC_BLE, LOW);
Running = false;
VLCStopped = true;
Serial.println("VLC STOP----------------------------- ") ;
}
} //stop vlc
//***Relay swtiching****
void RelayEvent()
{
Serial.println("Relay Event: ");
if(doTrigger < numberofEventTriggers && !EventArrayComplete)
{
LevelCheck(); // Change levels if needed
RelayOn(); // Option1 Relay always on
doTrigger++;
//levels changed
Serial.print("Next Array in Event position: ");Serial.println(doTrigger);
//EventArrayComplete
if (doTrigger == numberofEventTriggers)
{
EventArrayComplete = true;
Serial.println("Relay Array Complete");
}
else{
//advance arrays
performEvent_ms = EventTime[doTrigger] * 1000; //convert to milliseconds
NewLevel = EventLevel[doTrigger];
} //end else
} //end if
}
void RelayOn()
{
Serial.println("Relay on ");
digitalWrite(RelayPin, HIGH);
RelayState = digitalRead(RelayPin);
Serial.print("RelayState ") ;Serial.println(RelayState) ;
//comment out below if Option1 relay always on
RelaySwitchOffTime = (performEvent_ms + durationAction); // time when to switch relay off
}
void RelayOff()
{
Serial.println("Relay off ");
digitalWrite(RelayPin, LOW);
RelayState = digitalRead(RelayPin);
Serial.print("RelayState ") ;Serial.println(RelayState) ;
durationAction = durationTime[doTrigger]; //Load next time off
}
//****Pump Switching****
//Future send via ESPnow
void PumpEvent()
{
if(doPump < numberofPumpTriggers && !PumpArrayComplete)
{
Serial.println("Pump Event: ");
PumpOn(); // Option1 Relay always on
//advance arrays
doPump++;
if (doPump == numberofPumpTriggers)
{
PumpArrayComplete = true;
Serial.println("Pump Array Complete");
}
else{
Serial.print("Next Pump Array position: ");Serial.println(doPump);
PumpOnEvent_ms = PumpSwitchOn[doPump] * 1000; //convert to milliseconds
}
} //end if(doPum
}
void PumpOn()
{
Serial.println("PumpPwr on ");
digitalWrite(PumpPwr, HIGH);
bool PumpState = digitalRead(PumpPwr);
PumpPwrState = true;
Serial.print("PumpPwrState ") ;Serial.println(PumpState) ;
//comment out if Option1 relay always on
PumpSwitchOffTime = (PumpOnEvent_ms + durationPump); // time when to switch relay off
}
void PumpOff()
{
Serial.println("PumpPwr off ");
digitalWrite(PumpPwr, LOW);
digitalWrite(airValve, LOW); //air valve off at the same time pump switces off
bool PumpState = digitalRead(PumpPwr);
bool airValveState = digitalRead(airValve);
PumpPwrState = false;
airValvePwrState = false;
Serial.print("PumpPwrState ") ;Serial.println(PumpState) ;
Serial.print("airValveState ") ;Serial.println(airValveState) ;
durationPump = PumpdurationTime[doPump]; //Load next time to switch pump and valve off
}
//*******************************************************************************
//AIR VALVE
//Future send via ESPnow to Pump board
void airValveEvent()
{
Serial.println("airValve Event: ");
airValveSwitchOn();
airValveOnEvent_ms = airValveOn[doPump] * 1000; //convert to milliseconds
}
void airValveSwitchOn()
{
//valve closes when pump switches off
Serial.println("airValve On: ");
digitalWrite(airValve, HIGH);
bool airValveState = digitalRead(airValve);
Serial.print("airValve State ") ;Serial.println(airValveState) ;
}
//***********************************************************************
void Stop()
{
Serial.println("STOP STOP****************************** ") ;
Running = false;
Stopped = true;
digitalWrite(RelayPin, LOW);
//send via ESPNOW
digitalWrite(PumpPwr, LOW);
digitalWrite(airValve, LOW);
digitalWrite(Magnet, LOW);
Stop_VLC(); //stop VLC
Serial.print("Stopped Running : " ) ;Serial.println(Running) ;
} //Stop
void End()
{
Serial.println("END END END END");
delay(1000);
return;
} //Stop