I try to figure out how Inevos dosing pump code works and how i can adapt it to my tank. Im planning to run up to a total of 8 dosing pumps, but going to start with 4 (Alk, Ca, Mg, ultramin-s).
I have copy and pasted the relevant pieces of Inevos code here and added some comments of how i think it works. But what I'm really struggle with is to figure out how the CalibrateDPumps function works. Can someone make an in-depth explanation what the code does, and how i interact with the code? And also check the comments if i got everything else right
Code: Select all
// Define Custom Memory Locations
#define Mem_I_CalDP1Vol 100
#define Mem_I_CalDP1Time 101
#define Mem_I_DP1Volume 102
#define Mem_I_CalDP2Vol 103
#define Mem_I_CalDP2Time 104
#define Mem_I_DP2Volume 105
#define Mem_I_CalDP3Vol 106
#define Mem_I_CalDP3Time 107
#define Mem_I_DP3Volume 108
#define Mem_B_AlkTarget 120
#define Mem_B_ResetMemory 199
void init_memory() {
// Initialize Custom Memory Locations
InternalMemory.write_int(Mem_I_CalDP1Vol,10);
InternalMemory.write_int(Mem_I_CalDP1Time,470);
InternalMemory.write_int(Mem_I_DP1Volume,42);
InternalMemory.write_int(Mem_I_CalDP2Vol,10);
InternalMemory.write_int(Mem_I_CalDP2Time,490);
InternalMemory.write_int(Mem_I_DP2Volume,42);
InternalMemory.write_int(Mem_I_CalDP3Vol,3);
InternalMemory.write_int(Mem_I_CalDP3Time,270);
InternalMemory.write_int(Mem_I_DP3Volume,0);
InternalMemory.write(Mem_B_AlkTarget,145);
InternalMemory.write(Mem_B_ResetMemory,false);
}
#define NUMBERS_8x16
// Define Portal Variables
#define Var_DPump1 1
#define Var_DPump2 2
#define Var_AlkAdjust 7
// Define Relay Ports by Name
#define VO_Calibrate Box2_Port7
#define VO_LockPorts Box2_Port8
#define DPump1 Box1_Port7
#define DPump2 Box1_Port8
////// Place global variable code below here
////// Place global variable code above here
// Setup on controller startup/reset
void setup()
{
if (InternalMemory.read(Mem_B_ResetMemory))
init_memory();
////// Place additional initialization code above here
}
void loop()
{
////// Place your custom code below here
// Automation
RunDosingPumps(); // Dose by volume or time
CalibrateDPumps(); // Calibrate Dosing pumps
adjustAlk(); // Adjust Alkalinity to desired PPM (thanks AlanM)
LogDosingPumps(); // Keep track of dosing
LockPorts(); // Clear overrides for critical ports
////// Place your custom code above here
// This should always be the last line
}
// Definitions for dosing pumps !!!! Do we define this in memory, not variables?
#define numDPumps 3
byte pump[numDPumps]={ DPump1, DPump2, Extension}; // Pump 3 is just for logging/calibration routine
byte varReport[numDPumps]={ Var_DPump1, Var_DPump2, Var_WCVol}; // For reporting
byte memDPTime[numDPumps]={ Mem_B_DP1Timer, Mem_B_DP2Timer, Mem_B_DP3Timer}; //Dosing by time?
int memDPVolume[numDPumps]={ Mem_I_DP1Volume, Mem_I_DP2Volume, Mem_I_DP3Volume }; //Total volume dosing in 1 day?
int memDPRepeat[numDPumps]={ Mem_I_DP1RepeatInterval, Mem_I_DP2RepeatInterval, Mem_I_DP3RepeatInterval }; //Repeatinterval
int memCalTime[numDPumps]={ Mem_I_CalDP1Time, Mem_I_CalDP2Time, Mem_I_CalDP3Time }; //For calibration
int memCalVol[numDPumps]={ Mem_I_CalDP1Vol, Mem_I_CalDP2Vol, Mem_I_CalDP3Vol }; //For calibration
void RunDosingPumps() {
float rate;
byte dpTime;
int dpRepeat, calcTime, totalVolume;
const int numPumps = numDPumps-1; // -1 = Remove "Extension" from the equation.
static byte doseTime[numPumps]={
InternalMemory.read(memDPTime[0]),
InternalMemory.read(memDPTime[1])
};
for (int i=0;i < numPumps; i++) {
dpTime=InternalMemory.read(memDPTime[i]);
dpRepeat=InternalMemory.read_int(memDPRepeat[i]);
rate=(float)InternalMemory.read_int(memCalVol[i])/InternalMemory.read_int(memCalTime[i]); // Example: 100 ml in 600 seconds = 0,1666 ml/s
calcTime=(InternalMemory.read_int(memDPVolume[i])/rate)/(1440/dpRepeat); //example: we want to dose 60 ml total in one day
// 60ml / 0,1666 = total 361,44 seconds of dosing.
// one day equals to 1440 minutes? if we want to dose every hour then:
// calctime= 361,44/(1440/60)=361,44/24=15,06 seconds of dosing each time. correctly?
totalVolume=rate*(dpTime*(1440/dpRepeat)); // If using the above logic: 0,166*(15,06*(24))=0,166*361,44 = 59,99 ml, without rounding should ad up
if (dpTime!=doseTime[i])
{ // Memory has changed.
InternalMemory.write_int(memDPVolume[i], totalVolume); // Update volume
doseTime[i]=dpTime;
} else if (dpTime!=calcTime)
{ // Calculated time has changed.
InternalMemory.write(memDPTime[i], calcTime); // Update time
doseTime[i]=calcTime;
}
// Make sure we're not calibrating
if (!ReefAngel.Relay.Status(VO_Calibrate))
ReefAngel.DosingPumpRepeat(pump[i], i*5, dpRepeat, doseTime[i]);
}
}
void CalibrateDPumps() {
static time_t pumpTimer[numDPumps];
static boolean pumpStatus[numDPumps];
static boolean running=false;
if (ReefAngel.Relay.Status(VO_Calibrate))
{
running=true;
for (int i=0;i < numDPumps;i++)
{
if (ReefAngel.Relay.Status(pump[i]))
{
if (!pumpStatus[i])
{
pumpTimer[i]=now()-pumpTimer[i]; // Pump was off, timer is now a time
pumpStatus[i]=true;
}
} else
{
if (pumpStatus[i])
{
pumpTimer[i]=now()-pumpTimer[i]; // Pump was on, timer is now a timer
pumpStatus[i]=false;
}
}
}
} else
{
if (running)
{
running=false;
for (int i=0;i < numDPumps;i++)
{
if (pumpTimer[i]>0 && !ReefAngel.Relay.Status(VO_LockPorts))
{
InternalMemory.write_int(memCalTime[i], pumpTimer[i]);
}
ReefAngel.Relay.Override(pump[i],2); // Go back to auto mode
pumpStatus[i]=false;
pumpTimer[i]=0;
}
}
}
}