Page 1 of 5
Re: Dosing Pump not running on Schedule
Posted: Fri May 24, 2013 7:45 pm
by kirkwood
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
Re: Dosing Pump not running on Schedule
Posted: Fri May 24, 2013 7:50 pm
by cosmith71
rimai wrote:
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.
How might this be coded? Using an actual port, or a virtual one?
--Colin
Re: Dosing Pump not running on Schedule
Posted: Fri May 24, 2013 7:56 pm
by rimai
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
Take a look at this thread about Custom Main screens:
http://forum.reefangel.com/viewtopic.php?f=14&t=109
Basically a way to create your own screen
Re: Dosing Pump not running on Schedule
Posted: Fri May 24, 2013 7:59 pm
by rimai
cosmith71 wrote:rimai wrote:
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.
How might this be coded? Using an actual port, or a virtual one?
--Colin
It's actually an actual port, but could be considered as virtual, because you are using a port from a relay box that you don't have the physical box itself.
For example, if you code anything for Box1_Port1, it will use port1 of the expansion box 1, but if you don't have that physical box, nothing will be turned on/off, but as far as the controller is concerned, it is treating as if it was there.
Re: Dosing Pump not running on Schedule
Posted: Fri May 24, 2013 8:13 pm
by cosmith71
rimai wrote:cosmith71 wrote:rimai wrote:
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.
How might this be coded? Using an actual port, or a virtual one?
--Colin
It's actually an actual port, but could be considered as virtual, because you are using a port from a relay box that you don't have the physical box itself.
For example, if you code anything for Box1_Port1, it will use port1 of the expansion box 1, but if you don't have that physical box, nothing will be turned on/off, but as far as the controller is concerned, it is treating as if it was there.
OK, got that part. Is there an easy way to turn on a port for a specified amount of time?
if (ReefAngel.Relay.Status(AlkPump))
{ Turn on another port for 5 minutes } // not sure what this functinon would be
--Colin
Re: Dosing Pump not running on Schedule
Posted: Fri May 24, 2013 8:26 pm
by rimai
The easy way to do without having to declare new variables is to use the timers, but we only have 2 available.
Timer[1] and Timer[2].
The other option is to declare a new global variable that holds the time the change has happened.
Something like this:
Code: Select all
unsigned long LastUpdate=0;
..
..
..
void loop()
{
if (ReefAngel.Relay.Status(AlkPump) && LastUpdate==0)
{
LastUpdate=now();
}
if (now()-LastUpdate>=300 && LastUpdate!=0)
{
LastUpdate=0;
// Do something;
}
}
Re: Dosing Pump not running on Schedule
Posted: Fri May 24, 2013 8:42 pm
by cosmith71
It's too late at night for me to wrap my head around this. I think I have the tools I need. I'll work on it Monday when I'm off again. I think it'll be a fun project for me.
--Colin
Dosing Pump not running on Schedule
Posted: Sat May 25, 2013 6:18 am
by lnevo
Roberto,
What were you thinking on how to instantiate 8 different calibrations? From a menu? What would you use to pass in which relay we were calibrating?
The function I wrote does my two pumps at the same time.
Just trying to figure out how the interaction would work.
Re: Dosing Pump not running on Schedule
Posted: Sat May 25, 2013 8:59 am
by rimai
I didn't think of anything

I've been focusing on the touch unit and the upcoming products... sorry...
Re: Dosing Pump not running on Schedule
Posted: Sat May 25, 2013 11:53 am
by cosmith71
Roberto, how does now() work? What does it return?
Thanks,
--Colin
Re: Dosing Pump not running on Schedule
Posted: Sat May 25, 2013 11:56 am
by rimai
It returns unix time, which is often called epoch time too.
Basically it is number of seconds from 01/01/1970.
Re: Dosing Pump not running on Schedule
Posted: Sat May 25, 2013 9:05 pm
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?
Re: Dosing Pump not running on Schedule
Posted: Sun May 26, 2013 6:21 am
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
Re: Dosing Pump not running on Schedule
Posted: Sun May 26, 2013 6:27 am
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
Re: Dosing Pump not running on Schedule
Posted: Sun May 26, 2013 7:20 am
by rimai
Cool!!

Re: Dosing Pump not running on Schedule
Posted: Sun May 26, 2013 7:41 am
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...
I was a Comp Sci major 20 or so years ago. I never finished it. I'd forgotten how much fun coding can be.
--Colin
Re: Dosing Pump not running on Schedule
Posted: Tue May 28, 2013 6:47 pm
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...
Re: Dosing Pump not running on Schedule
Posted: Tue May 28, 2013 10:16 pm
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);
}
}
Re: Dosing Pump not running on Schedule
Posted: Wed May 29, 2013 5:29 am
by lnevo
Fixed the compile issues in the code above.
Re: Dosing Pump not running on Schedule
Posted: Wed May 29, 2013 4:47 pm
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;
}
}
}
}
Re: Dosing Pump not running on Schedule
Posted: Wed May 29, 2013 10:33 pm
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,
Re: Dosing Pump not running on Schedule
Posted: Thu May 30, 2013 7:28 am
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.
Re: Dosing Pump not running on Schedule
Posted: Thu May 30, 2013 7:38 am
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
Re: Dosing Pump not running on Schedule
Posted: Thu May 30, 2013 7:43 am
by cosmith71
Where does VO_Calibrate come from?
--Colin
Re: Dosing Pump not running on Schedule
Posted: Thu May 30, 2013 7:44 am
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.
Re: Dosing Pump not running on Schedule
Posted: Thu May 30, 2013 7:46 am
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
Re: Dosing Pump not running on Schedule
Posted: Thu May 30, 2013 7:49 am
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.
Re: Dosing Pump not running on Schedule
Posted: Thu May 30, 2013 7:51 am
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.
Re: Dosing Pump not running on Schedule
Posted: Sat Jun 01, 2013 6:58 am
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;
}
}
}
}
Re: Dosing Pump not running on Schedule
Posted: Mon Jun 10, 2013 10:48 am
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?