Page 1 of 1
Reversing the ATO code
Posted: Sun May 08, 2011 10:30 pm
by alexwbush
I want to reprogram my ATO program to work in a more logical way. I am using single ATO. I don't like how the switch is upside down with the wires in the water. Here is the function called in the main pde:
and the code that I think I need to modify in ReefAngel.cpp
Code: Select all
void ReefAngelClass::SingleATO(bool bLow, byte ATORelay, byte byteTimeout, byte byteHrInterval)
{
// if switch is active, stop the pump because the resevoir is full
// when the switch is not active, we need to turn on the relay to fill up resevoir
bool bCanRun = true;
static int iLastTop = 0;
if ( byteHrInterval )
{
int iSafeTop = NumMins(hour(), minute()) - iLastTop;
if ( iSafeTop < 0 )
{
iSafeTop += 1440;
}
if ( iSafeTop < (byteHrInterval * 60) )
{
bCanRun = false;
}
}
ReefAngel_ATOClass *ato;
if ( bLow )
{
ato = &LowATO;
}
else
{
ato = &HighATO;
}
unsigned long t = byteTimeout;
t *= 1000;
if ( ato->IsActive() )
{
iLastTop = NumMins(hour(), minute());
ato->StopTopping();
Relay.Off(ATORelay);
}
else if ( !ato->IsTopping() )
{
if ( bCanRun )
{
ato->Timer = millis();
ato->StartTopping();
Relay.On(ATORelay);
}
}
if ( (millis() - ato->Timer > t) && ato->IsTopping() )
{
LED.On();
Relay.Off(ATORelay);
}
}
any insight?
Re: Reversing the ATO code
Posted: Tue May 10, 2011 8:04 pm
by rimai
I'm pretty sure that if you are using the SingleATO function, it should be pointing down and not up.
Only if you are using the StandardATO is that you have they pointing to opposite sides.
Re: Reversing the ATO code
Posted: Wed May 11, 2011 5:43 am
by binder
rimai wrote:I'm pretty sure that if you are using the SingleATO function, it should be pointing down and not up.
Only if you are using the StandardATO is that you have they pointing to opposite sides.
I'm pretty sure you are correct too. The "IsActive" code means that when the float switch is touching the contacts on the same side of the wires. Which means that the wires will be up and out of the water. I do not have access to test and confirm this right now, but I believe it is correct.
curt
Re: Reversing the ATO code
Posted: Wed May 11, 2011 12:06 pm
by YuppiWanna
The thing with the floats that come with Reef Angel is they're not reversable right?
Re: Reversing the ATO code
Posted: Thu May 12, 2011 8:22 am
by rimai
Not reversable, but you could always program it to work the way you want.
Re: Reversing the ATO code
Posted: Tue May 24, 2011 9:28 pm
by alexwbush
So the SingleATOHigh function is opposite of what I want. I just rewired my ATO switches how I want them. Both face down and are in series. I intend to have them plugged into to "high ATO". How can I modify the code to make this work correctly? I tested it and at rest (both touching the bottom in this picture) nothing turns on. When I put either one of them up the circuit is broken and the port will turn on.
At the rest (both touching bottom as in the picture), I want the port to turn on. If
either switch is floating up out of rest mode, I want the port to turn off. I've always had my ATO wired this way. The lower floating (off rest) is the normal water level. If it drops down and the float rests on the bottom, top off activates. If the lower switch is stuck for some reason and doesn't float up, when the top off gets to the upper float it will turn off once that switch floats.
Please help. I am pretty sure this is going to require some coding. I will be coding as I wait, but I don't think there is a prebuilt function for this setup... which is strange because I thought this is how 80% of reefers have their ATO's setup.
I am using the development libraries.
Re: Reversing the ATO code
Posted: Tue May 24, 2011 11:51 pm
by alexwbush
Woo! I am starting to get the hang of programming!
Here's what I did:
Code: Select all
if(ReefAngel.HighATO.IsActive())
{
ReefAngel.Relay.On(Port1);
ReefAngel.Relay.On(Box1_Port6);
}
if(ReefAngel.HighATO.IsActive()==false)
{
ReefAngel.Relay.Off(Port1);
ReefAngel.Relay.Off(Box1_Port6);
}
Note: Box1_Port6 is for my water change system.
I'll be working on the automated water change over the next few weeks! Roberto, I'll email you for my other items.
Re: Reversing the ATO code
Posted: Sun Jun 05, 2011 3:01 pm
by astralmind
alexwbush wrote:
At the rest (both touching bottom as in the picture), I want the port to turn on. If either switch is floating up out of rest mode, I want the port to turn off. I've always had my ATO wired this way. The lower floating (off rest) is the normal water level. If it drops down and the float rests on the bottom, top off activates. If the lower switch is stuck for some reason and doesn't float up, when the top off gets to the upper float it will turn off once that switch floats.
Please help. I am pretty sure this is going to require some coding. I will be coding as I wait, but I don't think there is a prebuilt function for this setup... which is strange because I thought this is how 80% of reefers have their ATO's setup.
I am using the development libraries.
Wait, I'm confused. What you are describing is how all ATO system I know of behave.
Main switch:
Triggers ATO pump when the water level goes low enough for the switch to close (ie, the ring part stops floating and touches the bottom making contact).
Secondary switch:
As a safety, if the other switch remains stuck in closed position, the high switch shutsdown the ATO if the water level reaches it (ie, the ring part starts floating, cutting contact).
All in all both switches behave identically, one is just a redundant safety.
I was under the impression that SingleATO took care of that as opposit to the standardATO function ? Esle, why would there be 2 functions that serve the exact same purpose?
That being said I just generated some code using singleATO (high and low) and it does appear to completely inversed.
Interval is how long it takes before the function can be activated again and
timeout is the max amount of time the function will run regardless of the switch state correct ?
Some help on how to solve this would be immensly appreciated.
Thanks!
Re: Reversing the ATO code
Posted: Sun Jun 05, 2011 4:20 pm
by astralmind
Well, I had a look at both classes (Single and Standard) and thought it would be very simple to convert the StandardATO into what I (and I believe a few others) were looking for. Nothing spectacular and certainly not 100% safe so before you go on using this lets wait for Roberto or Curt who could validate it or certainly make it better.
For this to work you need to use the StandardATO function and modify it in ReefAngel.cpp (bad because it will be over written each time a new library update is published). Replace your StandardATO class with this one:
Code: Select all
void ReefAngelClass::StandardATO(byte ATORelay, int ATOTimeout)
{
// Input: Relay port and timeout value (max number of seconds that ATO pump is allowed to run)
unsigned long TempTimeout = ATOTimeout;
TempTimeout *= 1000;
/*
Is the low switch active (meaning we need to top off) and are we not currently topping off
Then we set the timer to be now and start the topping pump
*/
if ( LowATO.IsActive() && ( !LowATO.IsTopping())&& HighATO.IsActive() )
{
LowATO.Timer = millis();
LowATO.StartTopping();
Relay.On(ATORelay);
}
/*
Removed HighATO stop condition and replaced it with this statement. If one of the
2 switches is NOT active while the Top off is ongoing, stop top off
*/
if ( ((!LowATO.IsActive()) || !HighATO.IsActive()) && LowATO.IsTopping())
{
LowATO.StopTopping(); // stop the low ato timer
Relay.Off(ATORelay);
}
/*
If the current time minus the start time of the ATO pump is greater than the specified timeout value
AND the ATO pump is currently running:
We turn on the status LED and shut off the ATO pump
This prevents the ATO pump from contniously running.
*/
if ( (millis()-LowATO.Timer > TempTimeout) && LowATO.IsTopping() )
{
LED.On();
Relay.Off(ATORelay);
}
}
All that was changed is the stop condition which instead of waiting for the HighATO to be triggered (upside down) simply checks if one or both switches aren't active anymore. The only disavantage (besides it residing in the core code) is that you can't set an interval when using StandardATO.
What do you guys think ? Anyways to do this in a standard PDE without butchering the original code ?
Re: Reversing the ATO code
Posted: Sun Jun 05, 2011 5:54 pm
by alexwbush
Initially I tried to modify the ReefAngel.cpp code to work with single ATO the way I have it build (see picture above) and I couldn't get it to work correctly. Then I was told that the code is designed such that the code was built to have the float switches upside down.
I ended up coding the way I posted above and it's worked great. I don't need the timer since I have the second float switch to catch a problem and having the timer may hurt you if you're away from home and can't reset it without doing so at the source. The only thing that could go wrong with my setup/code is if your sump were leaking or your skimmer went crazy and wet skimmed (which mine did), but even then if can only fill as much as the ATO has, which for me is 5 gal. I left my setup for a week and just recently adjusted the skimmer (big mistake) and it ended up skimming almost 5 gal out which was replaced by RO water. It lowered the salinity significantly and I was a bit worried while I was away. A salinity probe would have let me know this while I was gone (hint, hint Roberto), but it seems everything survived.
Re: Reversing the ATO code
Posted: Sun Jun 05, 2011 6:06 pm
by astralmind
alexwbush wrote:Initially I tried to modify the ReefAngel.cpp code to work with single ATO the way I have it build (see picture above) and I couldn't get it to work correctly. Then I was told that the code is designed such that the code was built to have the float switches upside down.
I ended up coding the way I posted above and it's worked great. I don't need the timer since I have the second float switch to catch a problem and having the timer may hurt you if you're away from home and can't reset it without doing so at the source. The only thing that could go wrong with my setup/code is if your sump were leaking or your skimmer went crazy and wet skimmed (which mine did), but even then if can only fill as much as the ATO has, which for me is 5 gal. I left my setup for a week and just recently adjusted the skimmer (big mistake) and it ended up skimming almost 5 gal out which was replaced by RO water. It lowered the salinity significantly and I was a bit worried while I was away. A salinity probe would have let me know this while I was gone (hint, hint Roberto), but it seems everything survived.
Ha yes a salinity probe will surely be a welcomed addition!
So I saw your code for the highATO which is very straight forward but how did you take care of the primary switch (low ATO) ?
What did you mean by having to reset the timer ? hmmm so the default is set to operate for 60 seconds and then stop regardless of the switch state. Do that mean that it won't restart again on its own ever ? That must have been the purpose of the Interval function, act as some kind of a reset option?.
Re: Reversing the ATO code
Posted: Sun Jun 05, 2011 6:32 pm
by binder
astralmind wrote:
Wait, I'm confused. What you are describing is how all ATO system I know of behave.
Main switch:
Triggers ATO pump when the water level goes low enough for the switch to close (ie, the ring part stops floating and touches the bottom making contact).
Secondary switch:
As a safety, if the other switch remains stuck in closed position, the high switch shutsdown the ATO if the water level reaches it (ie, the ring part starts floating, cutting contact).
All in all both switches behave identically, one is just a redundant safety.
I was under the impression that SingleATO took care of that as opposit to the standardATO function ? Esle, why would there be 2 functions that serve the exact same purpose?
That being said I just generated some code using singleATO (high and low) and it does appear to completely inversed.
Interval is how long it takes before the function can be activated again and timeout is the max amount of time the function will run regardless of the switch state correct ?
There seems to be some confusion about what is considered floating or not floating and what is considered active or not active. It's not just the people commenting here, it's just in general.
IsActive - Means the float is
not touching the end with both wires coming out of it. So when the code says "ato->IsActive()" that means that the float is not touching the end with the wires.
With this being said, here is the way the StandardATO function works (it may be listed above but I'm re-listing it because of the discussion).
- High switch mounted with wires at the bottom
- Low switch mounted with the wires at the top
- When water level lowers all the way to cause the low switch to be active (float is touching the opposite end with the 2 wires coming out of it), the ATO pump is turned on.
- The ATO pump runs until the water level raises the low switch up from making contact, continues to raise the water level until the high switch is active (float touching the opposite end of the 2 wires coming out of it). The ATO pump shuts off when the high switch is active OR if the ATO Timeout value is exceeded. The timeout prevents the pump from running too long in case the reservoir runs dry or something else happens.
- Water then evaporates out of the tank and lowers until the low switch is active.
- Repeat process
The SingleATO function works with an individual switch only. So there is no failsafe built in. The only failsafe is the timeout value.
- Switch mounted with 2 wires at bottom
- Water level with the float at the top is the starting point.
- When the water level drops, the float is no longer floating or active, so the ATO pump turns on.
- It pumps in water until the float is active (touching the top end which is opposite the 2 wires) OR until the timeout value has exceeded. Then the pump shuts off.
- The hour interval just means that the ATO pump can only be activated once every X (specified) hours. This is to prevent it from activating too many times. You don't have to specify this if you don't want to. You can safely put in 0 and the ATO pump will activate as often as it needs.
- Repeat process
That should help clarify the 2 scenarios or sets of functions.
Yes, you are correct. Interval is the max time that the function can be activated again. Just pass in 0 to disable this check (like I stated above). Timeout is the max time that the pump will run during the current activation before the pump is shutoff. If this value is exceeded, then you either a) set it too short b) the reservoir is dry or c) the pump has failed/died/whatever and the switches will not tell the pump to stop. You will most likely not be triggering the activation again until the problem is fixed.
If you want to use the single ato functions and use the high switch as a failsafe, then you will have to look at the previous post by alex about how he coded is failsafe high switch into his PDE file. Here is his code:
I tweaked it to be an else statement because if it's active you do one thing and otherwise you do something else. It just looks better and there are less logical checks.
Code: Select all
if(ReefAngel.HighATO.IsActive())
{
ReefAngel.Relay.Off(Port1);
ReefAngel.Relay.Off(Box1_Port6);
}
else
{
ReefAngel.Relay.On(Port1);
ReefAngel.Relay.On(Box1_Port6);
}
This implies having the wires underwater (at the bottom).
Hope this helps.
curt
Re: Reversing the ATO code
Posted: Sun Jun 05, 2011 6:45 pm
by alexwbush
Thanks for simplifying my code curt. That makes sense. I'm a little rusty on my programming.
astralmind wrote:Ha yes a salinity probe will surely be a welcomed addition!
So I saw your code for the highATO which is very straight forward but how did you take care of the primary switch (low ATO) ?
What did you mean by having to reset the timer ? hmmm so the default is set to operate for 60 seconds and then stop regardless of the switch state. Do that mean that it won't restart again on its own ever ? That must have been the purpose of the Interval function, act as some kind of a reset option?.
I have my switches wired in series and plugged into the highATO receptical. That frees up my lowATO which I use to control my skimmer. My skimmer skims into a 2.5 or 5 gal bucket (depending on if I am out of town or not) and the skimmer will turn off if it fills the container... all part of my future auto water change setup and to keep my skimmer from going too crazy (which it already has one or two times).
Re: Reversing the ATO code
Posted: Sun Jun 05, 2011 8:06 pm
by astralmind
Thank you Curt for your detailed and very clear explanation aswell as Alex for your piece of code.
I will be using both low and high for now, with both switches in the upright position (wires upward). Whenever a switch floats, the port should be off since it means water as reached the proper level (low) or exceeded it and reached the second safety switch (high).
So in the end, if I get this right, this simple code in my PDE would do it:
Code: Select all
if(ReefAngel.HighATO.IsActive() && ReefAngel.LowATO.IsActive())
{
ReefAngel.Relay.On(Port1);
}
else
{
ReefAngel.Relay.Off(Port1);
}
I've just uploaded the code and it seems to work as intended. That being said (and it could be just me who's way too tired to look be looking at this

), it would mean that the IsActive state defines a switch that is not floating. With the above piece of code I could only get Port1 to turn on when both switches were hanging from their wires in an empty bin - exactly what I wanted.
Re: Reversing the ATO code
Posted: Mon Jun 06, 2011 6:14 am
by binder
astralmind wrote:
So in the end, if I get this right, this simple code in my PDE would do it:
Code: Select all
if(ReefAngel.HighATO.IsActive() && ReefAngel.LowATO.IsActive())
{
ReefAngel.Relay.On(Port1);
}
else
{
ReefAngel.Relay.Off(Port1);
}
I've just uploaded the code and it seems to work as intended. That being said (and it could be just me who's way too tired to look be looking at this

), it would mean that the IsActive state defines a switch that is not floating. With the above piece of code I could only get Port1 to turn on when both switches were hanging from their wires in an empty bin - exactly what I wanted.
One comment I have is about the redundancy. If the bottom switch fails and never activates for whatever reason, then using the Low and High IsActive together will FAIL. That logic check will only be true when BOTH switches are active and if the low switch isn't working that will never happen. So you don't want your failsafe to use both switches, you want it to ONLY use your high switch.
It sounds like you want the water level to be at the low switch with the high one as a backup. So going back to your initial request, here would be some logic for you: (This will assume both switches are wired with their wires at the top)
Code: Select all
void ATOFailSafe(byte port)
{
// Check for the low switch
/*
If the Low switch is active, meaning the float is opposite the end with the two wires,
we are empty so we should turn on the pump. Otherwise, we are full, so turn off the port.
*/
if ( ReefAngel.LowATO.IsActive() )
{
ReefAngel.LowATO.StartTopping();
ReefAngel.Relay.On(port);
}
else
{
ReefAngel.LowATO.StopTopping();
ReefAngel.Relay.Off(port);
}
if ( ReefAngel.LowATO.IsTopping() && ! ReefAngel.HighATO.IsActive() )
{
// We have a problem
/*
The pump is running and topping but the low switch isn't shutting off the port.
We must shutoff the port ourself.
*/
ReefAngel.Relay.Off(port);
// Trigger some sort of alert, maybe an email or text message
/*
We did not indicate that the port is not topping anymore, we could do that manually
OR we could not do it and replace the switch and have the controller do it for us.
It's completely up to the user.
At this point, it shouldn't matter because there is a problem with the switch and that
needs to be addressed.
*/
}
}
You can just copy and paste this function into your PDE file. Then inside your loop function, you can call it like this:
Code: Select all
void loop()
{
// other functions
ATOFailSafe(Port1);
}
This should handle your failsafe redundancy.
NOTE: This code does not use the timeouts at all and it does not use the hour interval. You would use this function instead of using the SingleATO or StandardATO functions.
Edited to indicate proper functionality with both wires at the top (coming out of the water) which is the reverse of how the SingleATO function works. SingleATO was based off of the high switch mounting/positioning from the StandardATO function.
curt
Re: Reversing the ATO code
Posted: Mon Jun 06, 2011 7:06 am
by astralmind
Once again, thank you very much for all your time and patience Curt, appreciated. I'll be sure to try your code as soon as I get home.
binder wrote:
Code: Select all
if(ReefAngel.HighATO.IsActive() && ReefAngel.LowATO.IsActive())
{
ReefAngel.Relay.On(Port1);
}
else
{
ReefAngel.Relay.Off(Port1);
}
If both switches are mounted with their wires upward, then that code will not work properly. IsActive state defines a switch that IS floating (touching the end with the wires). So in your code you listed, when BOTH floats are up (touching the ends with the wires), you are turning on your pump and shutting it off when they are down. You have the logic backwards. It should be:
This is were things get extremely odd. Your instructions were perfectly clear in that regard but unless there is an hardware issue here my setup is indeed working backward. The IsActive state (turn port on) gets triggered when the float switch
does not float (ie hangs at the bottom of the switch). If I have both switch in this position, the port is ON:
as soon as one of the switches starts to float (even lifted a tiny bit), the current is shut off. I tested this numerous time with a lamp and it worked as described (also properly reflected on the RA screen).
Are my float switches "inversed" or am I simply insane ?

Re: Reversing the ATO code
Posted: Mon Jun 06, 2011 7:12 am
by binder
astralmind wrote:
This is were things get extremely odd. Your instructions were perfectly clear in that regard but unless there is an hardware issue here my setup is indeed working backward. The IsActive state (turn port on) gets triggered when the float switch
does not float (ie hangs at the bottom of the switch). If I have both switch in this position, the port is ON:
as soon as one of the switches starts to float, the current is shut off. I tested this numerous time with a lamp and it worked as described (also properly reflected on the RA screen).
Are my float switches "inversed" or am I simply insane ?

No, you are not insane.
I was wrong.

I emphasized this because I will be the first to admit when I'm wrong. I don't deal with the ATO code much and it's confusing.
I wrote a PDE file to test the status for me and confirm how the IsActive function works. Here is the PDE that I wrote to test it (also attached to this post):
Code: Select all
#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>
void setup()
{
ReefAngel.Init(); //Initialize controller
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 10, 10, "ATO Status Screen");
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 10, 40, "Low:");
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 10, 60, "High:");
}
byte lowcolor;
char lowstatus[10];
byte highcolor;
char highstatus[10];
void loop()
{
if ( ReefAngel.LowATO.IsActive() )
{
lowcolor = COLOR_GREEN;
strcpy(lowstatus, "ACTIVE");
}
else
{
lowcolor = COLOR_RED;
strcpy(lowstatus, "INACTIVE");
}
if ( ReefAngel.HighATO.IsActive() )
{
highcolor = COLOR_GREEN;
strcpy(highstatus, "ACTIVE");
}
else
{
highcolor = COLOR_RED;
strcpy(highstatus, "INACTIVE");
}
ReefAngel.LCD.Clear(DefaultBGColor, 60, 40, 110, 48);
ReefAngel.LCD.Clear(DefaultBGColor, 60, 60, 110, 68);
ReefAngel.LCD.DrawText(lowcolor, DefaultBGColor, 60, 40, lowstatus);
ReefAngel.LCD.DrawText(highcolor, DefaultBGColor, 60, 60, highstatus);
delay(200);
}
So, based on this, you are absolutely correct with your float switches. I will be going back through and editing my post to be correct so others won't be confused when they read it. Bear with me for the time being on that.
curt
Re: Reversing the ATO code
Posted: Mon Jun 06, 2011 7:28 am
by astralmind
No worries Curt, I'm just happy that I got my sanity back
So in the end, the code I had written will be ok and will let me use timeouts, correct ?
Re: Reversing the ATO code
Posted: Mon Jun 06, 2011 7:42 am
by binder
astralmind wrote:No worries Curt, I'm just happy that I got my sanity back

It makes me lose my sanity too at times. hahaha
astralmind wrote:So in the end, the code I had written will be ok and will let me use timeouts, correct ?
The code you wrote would work but it wouldn't have a redundancy check like I mentioned a few posts ago. I have updated my code in the post to be correct now. It still does not have the timeouts.
So your code and my code does not incorporate the timeouts.
I'm honestly seriously considering changing the SingleATO function to have the float switches be mounted like the low switch in the StandardATO function (with the wires at the top). This would solve a lot of the confusion with everybody (myself included).
curt
Re: Reversing the ATO code
Posted: Mon Jun 06, 2011 7:59 am
by astralmind
binder wrote:
astralmind wrote:So in the end, the code I had written will be ok and will let me use timeouts, correct ?
The code you wrote would work but it wouldn't have a redundancy check like I mentioned a few posts ago. I have updated my code in the post to be correct now. It still does not have the timeouts.
So your code and my code does not incorporate the timeouts.
I'm honestly seriously considering changing the SingleATO function to have the float switches be mounted like the low switch in the StandardATO function (with the wires at the top). This would solve a lot of the confusion with everybody (myself included).
curt
Your code definitly makes sens to me however, I still don't understand why mine would not work as a failsafe considering that we now know for sure that the IsActive state is when the water level drops. Since I am using and "AND" argument, the port will not be triggered ON unless both switches are in a IsActive state.
If the low switch was defective (ie stuck in an isActive state, not rising up with the water level), the water level would eventually reach the High switch and trip it, making it float and breaking the if condition, stopping the top off.
The only potential issues I see with this is having either the High or low switch broken and stuck in a floating state, that would stop the ATO from ever kicking in. However this same issue would also happen with your code as far as I understand. With both piece of codes the risks are of "never topping off" VS overflowing which is probably less of an issue.
In the end I'm asking because the memory on the RA seems to be very limited and if we can save some bytes than, lets do it

Actually this is another concern all together but with my current extremely lite PDE (only WiFi and Temp checked in RAgen) and no addtionnal functions, I'm already pushing the limit.
Re: Reversing the ATO code
Posted: Tue Jun 07, 2011 11:59 pm
by alexwbush
I've been saying these switches were coded backwards for a while, but I think people thought I was that crazy old man in the village

Re: Reversing the ATO code
Posted: Wed Jun 08, 2011 12:24 pm
by astralmind
alexwbush wrote:I've been saying these switches were coded backwards for a while, but I think people thought I was that crazy old man in the village

make it 2 crazy old men in the village hehe
Having a great time learning about the code structure on this controller. I must say that the challenge is well worth the effort. I read through the Apex's 150 pages manual and found the "language" to be so restrictive and unclear at times.
Reef Angel sure rocks and the community behind it is a critical contributing factor.

Re: Reversing the ATO code
Posted: Fri Oct 07, 2011 9:31 am
by chase
binder wrote:
It sounds like you want the water level to be at the low switch with the high one as a backup. So going back to your initial request, here would be some logic for you: (This will assume both switches are wired with their wires at the top)
Code: Select all
void ATOFailSafe(byte port)
{
// Check for the low switch
/*
If the Low switch is active, meaning the float is opposite the end with the two wires,
we are empty so we should turn on the pump. Otherwise, we are full, so turn off the port.
*/
if ( ReefAngel.LowATO.IsActive() )
{
ReefAngel.LowATO.StartTopping();
ReefAngel.Relay.On(port);
}
else
{
ReefAngel.LowATO.StopTopping();
ReefAngel.Relay.Off(port);
}
if ( ReefAngel.LowATO.IsTopping() && ! ReefAngel.HighATO.IsActive() )
{
// We have a problem
/*
The pump is running and topping but the low switch isn't shutting off the port.
We must shutoff the port ourself.
*/
ReefAngel.Relay.Off(port);
// Trigger some sort of alert, maybe an email or text message
/*
We did not indicate that the port is not topping anymore, we could do that manually
OR we could not do it and replace the switch and have the controller do it for us.
It's completely up to the user.
At this point, it shouldn't matter because there is a problem with the switch and that
needs to be addressed.
*/
}
}
You can just copy and paste this function into your PDE file. Then inside your loop function, you can call it like this:
Code: Select all
void loop()
{
// other functions
ATOFailSafe(Port1);
}
This should handle your failsafe redundancy.
NOTE: This code does not use the timeouts at all and it does not use the hour interval. You would use this function instead of using the SingleATO or StandardATO functions.
Edited to indicate proper functionality with both wires at the top (coming out of the water) which is the reverse of how the SingleATO function works. SingleATO was based off of the high switch mounting/positioning from the StandardATO function.
curt
Trying to get this working but I'm getting the following error when compiling:
(#define Refugium 8 is highlighted yellow)
default_ragen_pde_all_ato_test:42: error: expected ',' or '...' before numeric constant
default_ragen_pde_all_ato_test:45: error: expected initializer before 'void'
Here's my PDE:
Code: Select all
// Autogenerated file by RAGen (v1.0.4.92), (09/08/2011 09:54)
// default_ragen_pde_all_ato_test.pde
//
// This version designed for v0.8.5 Beta 12 or later
/* The following features are enabled for this PDE File:
#define DisplayImages
#define WavemakerSetup
#define DateTimeSetup
#define VersionMenu
#define DirectTempSensor
#define DisplayLEDPWM
#define StandardLightSetup
*/
#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>
#define Daylight 1
#define ATO 2
//#define Chiller 2
#define Heater 3
#define Return 4
#define WavemakerL 5
#define WavemakerR 6
#define LED 7
#define Refugium 8
void setup()
void ATOFailSafe(byte ATO) //changed port to ATO
{
// Check for the low switch
/*
If the Low switch is active, meaning the float is opposite the end with the two wires,
we are empty so we should turn on the pump. Otherwise, we are full, so turn off the port.
*/
if ( ReefAngel.LowATO.IsActive() )
{
ReefAngel.LowATO.StartTopping();
ReefAngel.Relay.On(ATO);
}
else
{
ReefAngel.LowATO.StopTopping();
ReefAngel.Relay.Off(ATO);
}
if ( ReefAngel.LowATO.IsTopping() && ! ReefAngel.HighATO.IsActive() )
{
// We have a problem
/*
The pump is running and topping but the low switch isn't shutting off the port.
We must shutoff the port ourself.
*/
ReefAngel.Relay.Off(ATO);
// Trigger some sort of alert, maybe an email or text message
/*
We did not indicate that the port is not topping anymore, we could do that manually
OR we could not do it and replace the switch and have the controller do it for us.
It's completely up to the user.
At this point, it shouldn't matter because there is a problem with the switch and that
needs to be addressed.
*/
}
{
randomSeed(analogRead(0)); //wm stuff
ReefAngel.Init(); //Initialize controller
ReefAngel.FeedingModePorts = B00001000;
ReefAngel.WaterChangePorts = B00000000;
ReefAngel.OverheatShutoffPorts = B00000101;
ReefAngel.LightsOnPorts = B00000001;
// Ports that are always on
ReefAngel.Relay.On(Return); //port 4
//wm stuff
ReefAngel.Timer[1].SetInterval(random(15,35));
ReefAngel.Timer[1].Start();
ReefAngel.Relay.On(WavemakerL);
}
}
void loop()
{
ReefAngel.ShowInterface();
ReefAngel.StandardGUI(); //web connection
// ReefAngel.StandardFan(Chiller,775,783); Removed for ATO function
ReefAngel.StandardHeater(Heater,768,771);
ReefAngel.StandardLights(Daylight,9,0,19,30); //Daylight schedule 9:00am - 7:30pm
ReefAngel.StandardLights(Refugium,21,0,9,0); //Refugium schedule 9:00pm - 9:00am
ReefAngel.StandardLights(LED,8,30,22,0); //LED schedule 8:30am - 10:00pm
ATOFailSafe(ATO); //ATO Stuff
//Wavemaker stuff
if ( ReefAngel.Timer[1].IsTriggered() )
{
ReefAngel.Timer[1].SetInterval(random(15,30));
ReefAngel.Timer[1].Start();
ReefAngel.Relay.Toggle(WavemakerL); //port 5
ReefAngel.Relay.Toggle(WavemakerR); //port 6
}
/* Old ATO stuff
if(ReefAngel.LowATO.IsActive())
{
ReefAngel.Relay.On(ATO); //port 7
}
else
{
ReefAngel.Relay.Off(ATO);
}
*/
}
Thanks!!
Re: Reversing the ATO code
Posted: Fri Oct 07, 2011 9:35 am
by rimai
You can't use:
It's a reserved word for a the LED Class

Sorry.
Choose a different name
Re: Reversing the ATO code
Posted: Fri Oct 07, 2011 10:03 am
by chase
rimai wrote:You can't use:
It's a reserved word for a the LED Class

Sorry.
Choose a different name
Hmm, changed LED to Moonlight and I still get the same error(s). It compiles without the ATO code binder suggested (including the define LED reference) which is what I've been running for a while now with no issues.
Re: Reversing the ATO code
Posted: Fri Oct 07, 2011 10:09 am
by rimai
Ahhh...
After closer look, I had to change some stuff around.
Try this:
Code: Select all
// Autogenerated file by RAGen (v1.0.4.92), (09/08/2011 09:54)
// ATO_TEST.pde
//
// This version designed for v0.8.5 Beta 12 or later
/* The following features are enabled for this PDE File:
#define DisplayImages
#define WavemakerSetup
#define DateTimeSetup
#define VersionMenu
#define DirectTempSensor
#define DisplayLEDPWM
#define StandardLightSetup
*/
#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>
#define Daylight 1
#define AutoTopOff 2
//#define Chiller 2
#define Heater 3
#define Return 4
#define WavemakerL 5
#define WavemakerR 6
#define LED1 7
#define Refugium 8
void setup()
{
randomSeed(analogRead(0)); //wm stuff
ReefAngel.Init(); //Initialize controller
ReefAngel.FeedingModePorts = B00001000;
ReefAngel.WaterChangePorts = B00000000;
ReefAngel.OverheatShutoffPorts = B00000101;
ReefAngel.LightsOnPorts = B00000001;
// Ports that are always on
ReefAngel.Relay.On(Return); //port 4
//wm stuff
ReefAngel.Timer[1].SetInterval(random(15,35));
ReefAngel.Timer[1].Start();
ReefAngel.Relay.On(WavemakerL);
}
void loop()
{
ReefAngel.ShowInterface();
// ReefAngel.StandardFan(Chiller,775,783); Removed for ATO function
ReefAngel.StandardHeater(Heater,768,771);
ReefAngel.StandardLights(Daylight,9,0,19,30); //Daylight schedule 9:00am - 7:30pm
ReefAngel.StandardLights(Refugium,21,0,9,0); //Refugium schedule 9:00pm - 9:00am
ReefAngel.StandardLights(LED1,8,30,22,0); //LED schedule 8:30am - 10:00pm
ATOFailSafe(AutoTopOff); //ATO Stuff
//Wavemaker stuff
if ( ReefAngel.Timer[1].IsTriggered() )
{
ReefAngel.Timer[1].SetInterval(random(15,30));
ReefAngel.Timer[1].Start();
ReefAngel.Relay.Toggle(WavemakerL); //port 5
ReefAngel.Relay.Toggle(WavemakerR); //port 6
}
/* Old ATO stuff
if(ReefAngel.LowATO.IsActive())
{
ReefAngel.Relay.On(ATO); //port 7
}
else
{
ReefAngel.Relay.Off(ATO);
}
*/
}
void ATOFailSafe(byte ATO) //changed port to ATO
{
// Check for the low switch
/*
If the Low switch is active, meaning the float is opposite the end with the two wires,
we are empty so we should turn on the pump. Otherwise, we are full, so turn off the port.
*/
if ( ReefAngel.LowATO.IsActive() )
{
ReefAngel.LowATO.StartTopping();
ReefAngel.Relay.On(ATO);
}
else
{
ReefAngel.LowATO.StopTopping();
ReefAngel.Relay.Off(ATO);
}
if ( ReefAngel.LowATO.IsTopping() && ! ReefAngel.HighATO.IsActive() )
{
// We have a problem
/*
The pump is running and topping but the low switch isn't shutting off the port.
We must shutoff the port ourself.
*/
ReefAngel.Relay.Off(ATO);
// Trigger some sort of alert, maybe an email or text message
/*
We did not indicate that the port is not topping anymore, we could do that manually
OR we could not do it and replace the switch and have the controller do it for us.
It's completely up to the user.
At this point, it shouldn't matter because there is a problem with the switch and that
needs to be addressed.
*/
}
}
Re: Reversing the ATO code
Posted: Fri Oct 07, 2011 10:14 am
by chase
Winner- TY much!! Gonna upload it now...
