Dosing Pump not running on Schedule

Do you have a question on how to do something.
Ask in here.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Dosing Pump not running on Schedule

Post by rimai »

It returns unix time, which is often called epoch time too.
Basically it is number of seconds from 01/01/1970.
Roberto.
kirkwood
Posts: 173
Joined: Mon Apr 29, 2013 6:50 am

Re: Dosing Pump not running on Schedule

Post by kirkwood »

kirkwood wrote:Inevo,

I loaded in the code you posted. Where do I find the data it is tallying? I don't know what the "Custom main function" is.

thanks
so do I have to create a custom mainscreen to be able to utilize the code that I just added?
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Dosing Pump not running on Schedule

Post by cosmith71 »

lnevo wrote:Ok, try this...

Move this section above the setup where it says to put global code here...

Code: Select all

  
////// Place global variable code below here
time_t running1, running2;
You can leave this section in your loop();

Code: Select all

  // Reset the counter each day
  if (now()%SECS_PER_DAY==0) {
    running1=0;
    running2=0;
  }  
  
  // If the Dosing Pump 1 is on and it's a new second...
  if (ReefAngel.Relay.Status(DPump1) && (millis()%1000==0)) {
    running1++; // increment the counter;
  }

  // If the Dosing Pump is on and it's a new second...
  if (ReefAngel.Relay.Status(DPump2) && (millis()%1000==0)) {
    running2++; // increment the counter;
  }
  
  // Normalize and assign to CustomVar for reporting on the portal
  ReefAngel.CustomVar[0]=running1/60; // Number of Minutes for DPump1
  ReefAngel.CustomVar[1]=running1%60; // Number of Seconds for DPump1
  ReefAngel.CustomVar[2]=running2/60; // Number of Minutes for DPump2
  ReefAngel.CustomVar[3]=running2%60; // Number of Seconds for DPump2
You can now access running1 and running2 in your CustomMain function. If you want minutes and seconds look at the CustomVar assignments for how to do that, otherwise you could just display total seconds of running.

As far as ml, I'll try and get some time to do that later... I'm actually working on some code to store my calibration number and use a ml setting instead of second setting to distribute the amount throughout the day automatically.
Lee, I'm using the custom webchart and the android app to check this and all I get back from C0-C3 are zeros. Am I doing something wrong?

--Colin
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Dosing Pump not running on Schedule

Post by cosmith71 »

rimai wrote:You would have to make the running time longer than 5 minutes if you want it to show in the relay activity 100% of the time.
Or, you could code an expansion outlet port to be triggered on dosing pump port, but it would stay on for more than 5 minutes.
Done!

Code under "////// Place global variable code below here"

Code: Select all

unsigned long LastUpdate1=0;
unsigned long LastUpdate2=0;
Code in loop()

Code: Select all

if (ReefAngel.Relay.Status(AlkPump) && LastUpdate1==0)
    {
      LastUpdate1 = now();
      ReefAngel.Relay.On (Box2_Port1);
    }
    if (now() - LastUpdate1 >= 360 && LastUpdate1 != 0)
    {
      LastUpdate1 = 0;
      ReefAngel.Relay.Off (Box2_Port1);
    }
    
    if (ReefAngel.Relay.Status(CalPump) && LastUpdate2==0)
    {
      LastUpdate2 = now();
      ReefAngel.Relay.On (Box2_Port2);
    }
    if (now() - LastUpdate2 >= 360 && LastUpdate2 != 0)
    {
      LastUpdate2 = 0;
      ReefAngel.Relay.Off (Box2_Port2);
    }
Note, Box2 doesn't physically exist. Works like a charm. I doesn't give me times, but does let the portal relay chart tell me that the pumps came on.

--Colin
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Dosing Pump not running on Schedule

Post by rimai »

Cool!! :)
Roberto.
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Dosing Pump not running on Schedule

Post by cosmith71 »

I liked it so much I set it up for my ATO as well. Now my code is cluttered. Time to figure out how to move it into a function... :geek:

I was a Comp Sci major 20 or so years ago. I never finished it. I'd forgotten how much fun coding can be. :ugeek:

--Colin
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

So I'm thinking of switching to volume based. The only caveat is I think we also need to store the volume calibrated against. So for Roberto's case, using a 1cup kitchen measuring cup, you could set the volume to 236ml (1cup = 236.588ml). We can trigger a timer when mask on is set and stop the counter when mask off is set. Whatever the value of the timer is the number of seconds to fill that volume. We can have an time_t timers[] and the calibration function can take a byte ports[] as the argument. this way the function can calibrate all the pumps at once, or one at a time.

In a menu mode, you could show all the pumps that have been activated and the time and have an OK or Cancel button to save the settings. Or if you already know the rate and want to just plug it in you could just write the values to memory.

This would only work well if you have the wifi module...otherwise the menu becomes a lot more complicated...

Anyway, I'm going to change my code to go the volume route. I'm going to use the WiFiAlert method now to send me the time result...btw, this might be a good method for kirkwood...you can get an email each time your doser goes off with the total time / ml dosed each session...
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Ok, here's the function I wrote up to dose by volume or dose by time. If memory is flagged to dose by volume then it updates the DPTimer variable for that pump with the calculated time per dose. If not, it updates the memory location with how much volume should be dosed per day. This should make it easy to switch back and forth if needed. Also, should be easily adaptable to many dosing pumps, although you might want some by time and some by volume. still have to work on the new calibration function.

Once again this is test code, it has not even been compiled yet...

Code: Select all

void DosingPumps() {
  const byte numPumps=2;
  byte pump[numPumps] = { DPump1, DPump2 };
  
  int memTimer[numPumps] = { Mem_B_DP1Timer, Mem_B_DP2Timer };
  int memRepeat[numPumps] = { Mem_I_DP1RepeatInterval, Mem_I_DP2RepeatInterval };
  int memCalibrateVol[numPumps] = { Mem_I_Calibrate1Vol, Mem_I_Calibrate2Vol };
  int memCalibrateTime[numPumps] = { Mem_I_Calibrate1Time, Mem_I_Calibrate2Time };
  int memPumpVolume[numPumps] = { Mem_I_Pump1Vol, Mem_I_Pump2Vol };

  for (int i=0;i < numPumps; i++) {
    float pumpRate=InternalMemory.read_int(memCalibrateVol[i])/InternalMemory.read_int(memCalibrateTime[i]);
    int doseTime=InternalMemory.read_int(memTimer[i]);
    int repeatTime=InternalMemory.read_int(memRepeat[i]);
    int totalVolume=pumpRate*(doseTime*(1440/repeatTime));    
    int calcTime=(InternalMemory.read_int(memPumpVolume[i])*pumpRate)/(1440/repeatTime);

    if (InternalMemory.read(Mem_B_DoseByVolume)) {
      if (doseTime!=calcTime) 
        InternalMemory.write_int(memTimer[i], doseTime=calcTime); 
    } else {
      if (doseTime!=calcTime)
        InternalMemory.write_int(memPumpVolume[i], totalVolume);
    }
    
    ReefAngel.DosingPumpRepeat(pump[i], i*5, repeatTime, doseTime);
  }
}
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Fixed the compile issues in the code above.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Ok. calculations are working.. Not sure if I changed much except cast one float and had to change a multiply to divide :)

So if the mem location is set to dose by volume, when you change the volume memory field, it will update the timer for that dosing pump. Inversely if you update the timer when it's set to dose by time, it will update the volume memory location with the total volume for the day.

Still need to fix this so you can do either without needing to choose dose by volume or not... hmmm

Edit: Logging/Reporting... done. Method to cancel the calibration... done.

Anyway, here's some code to play with...

Code: Select all

// Definitions for dosing pumps
#define numDPumps 2
byte pump[numDPumps]={ DPump1, DPump2 };
byte varReport[numDPumps]={ Var_DPump1, Var_DPump2 };
int memDPTime[numDPumps]={ Mem_B_DP1Timer, Mem_B_DP2Timer };
int memDPVolume[numDPumps]={ Mem_I_DP1Volume, Mem_I_DP2Volume };
int memDPRepeat[numDPumps]={ Mem_I_DP1RepeatInterval, Mem_I_DP2RepeatInterval };
int memCalTime[numDPumps]={ Mem_I_CalDP1Time, Mem_I_CalDP2Time };
int memCalVol[numDPumps]={ Mem_I_CalDP1Vol, Mem_I_CalDP2Vol };

void RunDosingPumps() {
  int doseTime, repeatTime, calcTime, totalVolume;
  float rate;
  
  for (int i=0;i < numDPumps; i++) {
    doseTime=InternalMemory.read_int(memDPTime[i]);
    repeatTime=InternalMemory.read_int(memDPRepeat[i]);
    rate=(float)InternalMemory.read_int(memCalVol[i])/InternalMemory.read_int(memCalTime[i]);
    calcTime=(InternalMemory.read_int(memDPVolume[i])/rate)/(1440/repeatTime);
    totalVolume=rate*(doseTime*(1440/repeatTime));    
    
    if (InternalMemory.read(Mem_B_DoseByVolume)) {
      if (doseTime!=calcTime) 
        InternalMemory.write_int(memDPTime[i], doseTime=calcTime); 
    } else {
      if (doseTime!=calcTime)
        InternalMemory.write_int(memDPVolume[i], totalVolume);
    }
    
    // Make sure we're not calibrating
    if (!ReefAngel.Relay.Status(VO_Calibrate)) 
      ReefAngel.DosingPumpRepeat(pump[i], i*5, repeatTime, doseTime);
  }
}

void LogDosingPumps() {
  static time_t pumpTimer[numDPumps];
  static boolean pumpStatus[numDPumps];
  float rate;

  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;
    
        rate=(float)InternalMemory.read_int(memCalVol[i])/InternalMemory.read_int(memCalTime[i]);
        ReefAngel.CustomVar[varReport[i]]=pumpTimer[i]*rate;
      }
    }

    if (now()%SECS_PER_DAY==SECS_PER_DAY-1) pumpTimer[i]=0; // Clear timer at end of day
  }  
}

void CalibrateDPumps() {
  static time_t pumpTimer[numDPumps];
  static boolean pumpStatus[numDPumps];
  static boolean running;
      
  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: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

FYI, this code relies on a few things that I have added to the libraries but aren't available yet. If you want to use this let me know and I can either point you to my git repo for the current branch to pull, or how to work around the missing pieces,
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Ok, I took out the dependencies to WiFiAlert and the mask commands I added. I needed a solution anyway for the logging (which could have been on or a mask...) so I used the same mechanism in the calibration routine. So this should be usable by anyone now.

Also, since we are now calculating the rate of flow and are able to determine volume.. I think we can safely store the amount dosed in a byte and publish it to the portal.... if it wraps, it wraps :) But this should provide good monitoring for those who want to monitor their dosing routine.
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Dosing Pump not running on Schedule

Post by cosmith71 »

lnevo wrote:Ok, I took out the dependencies to WiFiAlert and the mask commands I added. I needed a solution anyway for the logging (which could have been on or a mask...) so I used the same mechanism in the calibration routine. So this should be usable by anyone now.

Also, since we are now calculating the rate of flow and are able to determine volume.. I think we can safely store the amount dosed in a byte and publish it to the portal.... if it wraps, it wraps :) But this should provide good monitoring for those who want to monitor their dosing routine.
This is the code in the last post on page 4? Might play with it over the weekend.

--Colin
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Dosing Pump not running on Schedule

Post by cosmith71 »

Where does VO_Calibrate come from?

--Colin
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Yea. The trick in using it is defining all the memory locations needed, but otherwise *should* be plug and play. I should be around to help if you get stuck on anything... There may be another version by the weekend though, as I have a few more tests to run, but I'm pretty pleased with it at the moment.
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Dosing Pump not running on Schedule

Post by cosmith71 »

lnevo wrote:Yea. The trick in using it is defining all the memory locations needed, but otherwise *should* be plug and play. I should be around to help if you get stuck on anything... There may be another version by the weekend though, as I have a few more tests to run, but I'm pretty pleased with it at the moment.
Which locations are available? Is it 100-199?

--Colin
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

You should use my INO (in my signature) as a reference for some of those defines :)

VO_Calibrate is a virtual (non-existent) outlet. You could use any unused outlet or change the conditional to use a memory location as a trigger. I use two ports to control the calibration process. One that locks the ports and one to start calibration mode. If I lock the ports before I turn off calibration mode, then the values are not saved. If I turn off calibration mode first then the time values are saved to memory.

Good question, and I guess where it might get tricky for some.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

cosmith71 wrote:
lnevo wrote:Yea. The trick in using it is defining all the memory locations needed, but otherwise *should* be plug and play. I should be around to help if you get stuck on anything... There may be another version by the weekend though, as I have a few more tests to run, but I'm pretty pleased with it at the moment.
Which locations are available? Is it 100-199?

--Colin
Yeah, those should be free to use if you aren't already. The built-ins start at 200.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Ok, for anyone testing, I've got all the bugs I think sorted out. The nice thing is that you can now update the volume memory location OR the DPTimer in the portal. If you change the volume, the new time is calculated and updated so you can see the change and the dosage amount in the portal. If you change the time however, it will get rounded to the nearest ml. So for instance if I put 68 seconds in the timer, it will calculate the volume of ml that will produce which will then be updated in memory. It will then recalculate the amount of time necessary to get that dosage which would then be 65 seconds. This is a precision issue since we can't store floats in memory (yet hehehe) But either way, the volume method would be the more accurate means to adjust at this point, but the functionality is in place.

Anyway, if anyone wants to play with this, here is the latest round of code:

Be aware, you will need to change the triggers in the calibration routine. Either declare ports that you are not using and they will appear in the portal as if you had an expansion relay or change the conditionals to use memory settings, or if you're brave, you could write a menu interface to turn on calibration and off. That part may get tricky so let me know if you have any questions.

Code: Select all

// Definitions for dosing pumps
#define numDPumps 2
byte pump[numDPumps]={ DPump1, DPump2 };
byte varReport[numDPumps]={ Var_DPump1, Var_DPump2 };
int memDPTime[numDPumps]={ Mem_B_DP1Timer, Mem_B_DP2Timer };
int memDPVolume[numDPumps]={ Mem_I_DP1Volume, Mem_I_DP2Volume };
int memDPRepeat[numDPumps]={ Mem_I_DP1RepeatInterval, Mem_I_DP2RepeatInterval };
int memCalTime[numDPumps]={ Mem_I_CalDP1Time, Mem_I_CalDP2Time };
int memCalVol[numDPumps]={ Mem_I_CalDP1Vol, Mem_I_CalDP2Vol };

void RunDosingPumps() {
  float rate;
  int dpTime, dpRepeat, calcTime, totalVolume;

  static int doseTime[numDPumps]={ 
    InternalMemory.read(memDPTime[0]), 
    InternalMemory.read(memDPTime[1]) 
  };
  
  for (int i=0;i < numDPumps; i++) {
    dpTime=InternalMemory.read(memDPTime[i]);
    dpRepeat=InternalMemory.read_int(memDPRepeat[i]);
    rate=(float)InternalMemory.read_int(memCalVol[i])/InternalMemory.read_int(memCalTime[i]);
    calcTime=(InternalMemory.read_int(memDPVolume[i])/rate)/(1440/dpRepeat);
    totalVolume=rate*(dpTime*(1440/dpRepeat)); 

    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 LogDosingPumps() {
  static time_t pumpTimer[numDPumps];
  static boolean pumpStatus[numDPumps];
  float rate;

  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;
    
        rate=(float)InternalMemory.read_int(memCalVol[i])/InternalMemory.read_int(memCalTime[i]);
        ReefAngel.CustomVar[varReport[i]]=pumpTimer[i]*rate;
      }
    }

    if (now()%SECS_PER_DAY==SECS_PER_DAY-1) pumpTimer[i]=0; // Clear timer at end of day
  }  
}

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;
      }
    }
  }    
}
kirkwood
Posts: 173
Joined: Mon Apr 29, 2013 6:50 am

Re: Dosing Pump not running on Schedule

Post by kirkwood »

lnevo wrote:Ok, try this...

Move this section above the setup where it says to put global code here...

Code: Select all

  
////// Place global variable code below here
time_t running1, running2;
You can leave this section in your loop();

Code: Select all

  // Reset the counter each day
  if (now()%SECS_PER_DAY==0) {
    running1=0;
    running2=0;
  }  
  
  // If the Dosing Pump 1 is on and it's a new second...
  if (ReefAngel.Relay.Status(DPump1) && (millis()%1000==0)) {
    running1++; // increment the counter;
  }

  // If the Dosing Pump is on and it's a new second...
  if (ReefAngel.Relay.Status(DPump2) && (millis()%1000==0)) {
    running2++; // increment the counter;
  }
  
  // Normalize and assign to CustomVar for reporting on the portal
  ReefAngel.CustomVar[0]=running1/60; // Number of Minutes for DPump1
  ReefAngel.CustomVar[1]=running1%60; // Number of Seconds for DPump1
  ReefAngel.CustomVar[2]=running2/60; // Number of Minutes for DPump2
  ReefAngel.CustomVar[3]=running2%60; // Number of Seconds for DPump2
You can now access running1 and running2 in your CustomMain function. If you want minutes and seconds look at the CustomVar assignments for how to do that, otherwise you could just display total seconds of running.

As far as ml, I'll try and get some time to do that later... I'm actually working on some code to store my calibration number and use a ml setting instead of second setting to distribute the amount throughout the day automatically.

I used this code and I don't get any value in the custom field 0 or 2. I do get a value in custom field 1 and 3. From reading the code it looks like fields 1 and 3 are for seconds. I usually get a reading that is a pretty small number while I'expect to see something that consistently approaches 60 before resetting. Seems like the minute fields are not funcitoning properl. How can I fix?
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Looking at the forum chart for your variables, it doesn't look like you're getting more than 13 seconds of dosing... the value climbs all day and resets at midnight as expected. It won't increment c0 or C2 until it gets passed 60 seconds... Your C3 variable peaked at 15 on friday...

Take a look at these charts if you haven't already. It may help to troubleshoot.

http://forum.reefangel.com/status/chart ... &filter=c1
http://forum.reefangel.com/status/chart ... &filter=c3

Can you confirm how much time your dosing each session?


Also, there may be an issue with the logic I used to increment the counter as you may not hit this function when milis%1000=0. I am using a different method in my other code, so I think this may be the bigger part of your problem. What I do now is start a timer when I see the port go on and disable the timer when it goes off.

If you can look at the LogDosingPumps() function in this post: http://forum.reefangel.com/viewtopic.php?p=27080#p27080 and see what I do now it may help... if you need assistance re-coding what your using, I can try and put something together later tonight.
kirkwood
Posts: 173
Joined: Mon Apr 29, 2013 6:50 am

Re: Dosing Pump not running on Schedule

Post by kirkwood »

Inevo,

I will take a look at those links later tonight. I know I run port 3 for 340 seconds ever 2 hours and port4 I run 290 seconds every 2 hours with a 60 minute offset.
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Cool, yeah I think it was the methodology I used. I will alter the function for you on the train ride home or later tonight.... sorry for the confusion.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Ok here is a bit of a merger from my current volume based code and what you were originally timing. This tracks how long in seconds the port is on and publishes it to the portal. If you turn it on or mask it on by mistake you could even set an alert... You could also trigger a mask off for the port in your code so your pumps are automatically disabled,..anyway I digress.l, here's the code

Code: Select all

#define numPumps=2
byte pump[numPumps] = { DPump1, DPump2 };
byte portalMinutes = { 0, 2 }
byte portalSeconds = { 1, 3 }

static time_t pumpTimer[numDPumps];
static boolean pumpStatus[numDPumps];
  
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;

      // Normalize and assign to CustomVar for reporting on the portal
      ReefAngel.CustomVar[portalMinutes[i]]=pumpTimer[i]/60; // Number of Minutes
      ReefAngel.CustomVar[portalSeconds[i]]=pumpTimer[i]%60; // Number of Seconds
    }
  }

  if (now()%SECS_PER_DAY==SECS_PER_DAY-1) pumpTimer[i]=0; // Clear timer at end of day
}  

User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Adding in tracking for the ATO pump as well.

Code: Select all

const byte numPumps=3;
byte pump[numPumps] = { DPump1, DPump2,  ATOPort };
byte portalMinutes[numPumps] = { 0, 2, 4 };
byte portalSeconds[numPumps] = { 1, 3, 5 };

static time_t pumpTimer[numPumps];
static boolean pumpStatus[numPumps];
static boolean atoDisabled;
  
for (int i=0;i< numPumps;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;

      // Normalize and assign to CustomVar for reporting on the portal
      ReefAngel.CustomVar[portalMinutes[i]]=pumpTimer[i]/60; // Number of Minutes
      ReefAngel.CustomVar[portalSeconds[i]]=pumpTimer[i]%60; // Number of Seconds
    }
  }
}


if (now()%SECS_PER_DAY==SECS_PER_DAY-1) pumpTimer[0]=0; // Clear timer for DPump1
if (now()%SECS_PER_DAY==SECS_PER_DAY-1) pumpTimer[1]=0; // Clear timer for DPump2

if (bitRead(ReefAngel.Relay.RelayMaskOff, Port1Bit)==0) { // ATO relay is manually disabled
  atoDisabled=true;
} 
if (atoDisabled && (bitRead(ReefAngel.Relay.RelayMaskOff, Port1Bit)==1)) { // ATO override has been cleared
  pumpTimer[2]=0; // Clear timer for ATOPort
  atoDisabled=false;
}

kirkwood
Posts: 173
Joined: Mon Apr 29, 2013 6:50 am

Re: Dosing Pump not running on Schedule

Post by kirkwood »

So I am assuming that I need to delete all the old code for the dosing pump logging from the global variable and custom code sections?

Next does all the new code go into the custom code or do I place some of the code in the global variable section?

Finally, do I need to change any of the DPump names to the actual Port numbers I am using?
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Yes, you will need to delete everything you added previously. I just fixed a few errors and made it so you can just copy / paste this into the custom section.

You will need to change the DPump1, DPump2, and ATOPort to your ports, or define them :)
You will also need to change the PortXBit to whatever port your ato is on for the timer reset to work.
kirkwood
Posts: 173
Joined: Mon Apr 29, 2013 6:50 am

Re: Dosing Pump not running on Schedule

Post by kirkwood »

My ALK is Port3, my CAL is Port4, my ATO is Port7. Did I make the correct changes?


const byte numPumps=3;
byte pump[numPumps] = { Port3, Port4, Port7 };
byte portalMinutes[numPumps] = { 0, 2, 4 };
byte portalSeconds[numPumps] = { 1, 3, 5 };

static time_t pumpTimer[numPumps];
static boolean pumpStatus[numPumps];
static boolean atoDisabled;

for (int i=0;i< numPumps;i++) {
if (ReefAngel.Relay.Status(pump)) {
if (!pumpStatus) {
pumpTimer=now()-pumpTimer; // Pump was off, timer is now a time
pumpStatus=true;
}
} else {
if (pumpStatus) {
pumpTimer=now()-pumpTimer; // Pump was on, timer is now a timer
pumpStatus=false;

// Normalize and assign to CustomVar for reporting on the portal
ReefAngel.CustomVar[portalMinutes]=pumpTimer[i]/60; // Number of Minutes
ReefAngel.CustomVar[portalSeconds[i]]=pumpTimer[i]%60; // Number of Seconds
}
}
}


if (now()%SECS_PER_DAY==SECS_PER_DAY-1) pumpTimer[0]=0; // Clear timer for DPump1
if (now()%SECS_PER_DAY==SECS_PER_DAY-1) pumpTimer[1]=0; // Clear timer for DPump2

if (bitRead(ReefAngel.Relay.RelayMaskOff, Port7Bit)==0) { // ATO relay is manually disabled
atoDisabled=true;
}
if (atoDisabled && (bitRead(ReefAngel.Relay.RelayMaskOff, Port7Bit)==1)) { // ATO override has been cleared
pumpTimer[2]=0; // Clear timer for ATOPort
atoDisabled=false;
}
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Dosing Pump not running on Schedule

Post by lnevo »

Looks good, let me know if any issues in the compile.
kirkwood
Posts: 173
Joined: Mon Apr 29, 2013 6:50 am

Re: Dosing Pump not running on Schedule

Post by kirkwood »

Error when compiling.
scalar object "portalMinutes" requires one element in initializer
Image
Post Reply