Inevos dosingpump code

Do you have a question on how to do something.
Ask in here.
Post Reply
Jim_J
Posts: 13
Joined: Sat Jun 15, 2013 3:21 pm

Inevos dosingpump code

Post by Jim_J »

Hi!

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;
      }
    }
  }    
}
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Inevos dosingpump code

Post by lnevo »

Hey I'll try and give a quick explanation of the calibration and then review the code later tonight. It seems good from first glance though.

One of the things your missing is my Lock Ports function. I use that to prevent the dosing pumps from accidentally being overwritten and either dosing non stop or not dosing. So the calibrate function assumes you've unlocked (turn off) the lock port relay.

So now that the lock relay is off you can turn on the calibration port. It will then keep track of how many seconds the dosing pump is on while you are calibrating. Set a stopwatch and let the port you want to measure run. When you've reached a specific volume then shut off the port. You can stop/start as much as you need to get to the volume you want. I recommend 10ml.

Next you can do one of two things. If you re-lock the port then it will not save the calibration time and it will cancel the calibration routine. So this is your Exit without Saving. If you turn off the calibration relay first it will save the time to the memory location for that relay. You will have to either pre-set the volume you will measure OR update the memory location with however much volume was actually dosed.

I hope that makes sense. I'll try and run through your code later tonight so if something was not clear, please ask and i can explain at that time.
Jim_J
Posts: 13
Joined: Sat Jun 15, 2013 3:21 pm

Re: Inevos dosingpump code

Post by Jim_J »

Great, thanks a lot!

Now i understand, Mem_I_CalDP*Vol is a fixed volume that we set in the memory trough a http request? I think i get a grip now, i will adapt the code to my setup and post it here :)

Really awesome coding, thanks Lee :)
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Inevos dosingpump code

Post by lnevo »

You could set it through http or use the init_memory function. You could comment out the if to force it to init on boot.

What I did was set volume to 11 and time to 660. This was a 1.1ml/minute then do the calibration to get a more accurate number.
Jim_J
Posts: 13
Joined: Sat Jun 15, 2013 3:21 pm

Re: Inevos dosingpump code

Post by Jim_J »

Have another question about this line:

Code: Select all

byte memDPTime[numDPumps]={ Mem_B_DP1Timer, Mem_B_DP2Timer, Mem_B_DP3Timer};
I found Mem_B_DP1Timer and Mem_B_DP2Timer in globals.h, but what about number 3? What does these memorylocations hold? In my case I'm going to use 4 dosing pumps, do i need to create custom memory locations for this?

Thanks again for all your help :)
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Inevos dosingpump code

Post by lnevo »

These are the stock timer locations for DP1,2, and 3. If you go beyond you'll have to create some custom locations.

I wasn't dosing with DP3 just using it to track my water change volume (which wasn't working btw...)
Jim_J
Posts: 13
Joined: Sat Jun 15, 2013 3:21 pm

Re: Inevos dosingpump code

Post by Jim_J »

Ok, thanks! What values does the timers hold, and what do they do?

Ok, so i could just skip the parts where you use the third dp?
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Inevos dosingpump code

Post by lnevo »

They are how much time the pump doses each interval.
Post Reply