Another Water change thread this one based on IO Mod floats

Do you have a question on how to do something.
Ask in here.
Post Reply
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Another Water change thread this one based on IO Mod floats

Post by 00Warpig00 »

rimai wrote:This is what I came up with:

Code: Select all

#include <Salinity.h>
#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

byte wc_status=0;

// 0 - Draining
// 1 - Filling up
// 2 - Finish
void setup()
{
  ReefAngel.Init();  
}

void loop()
{
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE)
  {
    byte TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox(10, 100, TempRelay);

    switch (wc_status)
    {
    case 0:
      ReefAngel.Relay.On(2);
      if (ReefAngel.LowATO.IsActive()) wc_status++;
      break;
    case 1:
      ReefAngel.Relay.Off(2);
      ReefAngel.Relay.On(4);
      if (!ReefAngel.HighATO.IsActive()) wc_status++;
      break;
    case 2:
      ReefAngel.Relay.Off(2);
      ReefAngel.Relay.Off(4);
      wc_status=0;
      ButtonPress++;
    }
  }
  ReefAngel.ShowInterface();
}

Saw this code in the other water change thread and I would like to get my water change programmed. I am still having trouble with float switches activating erroneously (Grrr..) but still want to trek on with my code so I can work on both in parallel and hopefully get this going sooner than later. I have been spending allot of time on the Arduino.CC site trying to grasp the concept of coding this myself but am not really comfortable writing anything elaborate like this yet. Figured I would get on here and re-post the previous code I saw and probably use it as a starting point as it seemed to work with good result for the OP and my ideas although seem to have more detail about what I need to do would probably still work with the above coding concept. If anyone wants to contribute some code for me that would be awesome, but I am also trying to learn a little about coding the ATMega 2560 and if only spoon fed some framework I *might* be able to make some progress on my own too. Is there a guide for the functions available and how to use them all for the reef angel libraries anywhere?

A little background or reminder on my setup if it matters.
Reef Angel+
Expansion Hub
Primary/Secondary Relay Expansion Boxes (16 outlets total)
Salinity Mod
IO Mod
1/2 PWM 1/2 Analog Dimming Mod
PH Probe
T1/T2/T3 Sensors
ATO based on the dual ATO method and working great (times out once in a while, but otherwise great)

I have 8 float switches in my system. 2 that seem to work ok and are in my return chamber of my sump for my dual ATO. The dual ATO has been working almost flawlessly for at least the past month :D just a timeout about once every other week (not sure why) but I have already dealt with that issue and can reset the timeout remotely to get going again. All is good.

The other 6 float switches are spread out amongst my RO Top off Brute. Two switches. One active empty, and one active full with a maxi jet at the bottom. My SW top off Brute is the same, one float active empty and one active full also with a maxi jet at the bottom. Both maxi jets deliver water to my sump for ATO/Water Change. My sump has two additional floats in it. One is active when sump is empty (1 inch of water left in sump) the other is active full (full is defined as just barely active when return pump is turned off and all back flow from tank drops into sump, this is also 85% physically full to boot) The sump also has a maxi jet at the bottom to pump old water down the drain during a water change.

I did a manual water change the other day. Manually replicated and performed all of the functions on the controller needed and wrote down what needs to happen in what order to perform a smooth water change on my setup. I don't plan to ever do an unattended water change at this time and will be standing by and watching the water change progress just because I will have to build up allot of confidence before I move 20+ gallons of water out and another 20+ gallons of water into my system and know there will be no problems without standing there. So for the indefinite future I will be supervising these water changes.

Here is what has to happen in my system and the order it must happen to do a water change by this method.

1.Enter water change mode

2.Check IF SW Brute is empty (IO Mod Port 2 Active?)
a.if active inform me of empty brute (chirp buzzer once?) then abort Water change and exit WC mode.

3.disable ATO mode somehow until WC mode is exited (I do WC by draining and refilling SUMP) don't want ATO trying to refill sump during this time. This may already happen in WC mode I'm not sure. If not it needs to. I found this out during my walk through that as soon as my low ato switch detected low water in the sump it kicked on my ato pump to resolve the issue. It didn't know I was draining on purpose. I unplugged both ATO float switches from controller to do this in my mock up after I discovered the issue.

4.Turn off skimmer (primary relay box port 4)
a.wait a period of time for skimmer to drain (1 minute)

5.Turn off Return pump. (primary relay box port 3)

6.Wait for Sump Full float switch to become active (IO Mod Port 1)
a.then wait an additional minute
b.turn on sump drain pump (primary relay box port 8)
c.wait for sump empty float switch to become active (IO Mod port 0)
d.turn off sump drain pump (primary relay box port 8)
e.turn on SW Brute pump (primary relay box port 7)
f.wait for sump full float switch to become active (IO Mod Port 1)
g.turn off SW Brute pump (primary relay box port 7)


7.Turn on Return Pump. (primary relay box port 3)

8.Wait a few minutes for water levels to become stable in sump and DT (3 minutes)

9.Turn On Skimmer

10.Wait for sump water level to become stable (2 minutes?)

11.enable ATO Logic (done moving water around in sump ready to exit WC mode)

12.exit Water Change mode.


So this is what I am looking to accomplish. Any guidance that anyone can offer someone new to arduino programming would be wonderful. I believe the framework in the code above may generally work for me too. I still need to decipher what it all means and will have to add to it to meet my needs.

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

As far as a guide to programming, there really doesn't exist one that I'm aware of. The programming for the arduino is in standard C/C++ (it's mostly C but does have several big features of C++ added in/enabled for our needs).

For the libraries, there used to be a list of functions that are available for you to use to program, but it's not really been kept up with due to the rapid changing of the libraries.

To accomplish what you are wanting to do (and I have not even looked at the sample reference code that you posted), it's best if this series of tasks be performed in a function all on it's own. The reason for this is to
  • 1. isolate all of the code and have it be easy to read inside your main loop
  • 2. during your automated water change, you're going to be having limited functionality
  • 3. the controller is going to be doing a set of specific tasks and isn't going to be monitoring in the standard way, only the way you want it to
  • 4. you will want an easy way of activating the water change either by selecting a menu item from a custom menu or by setting a value inside your internal memory to trigger the water change remotely via a smartphone app.
This will be utilizing parts of code from various other functions that are in the libraries to do the tasks. So we will be using parts of the WaterChange function as well as the ATO functions. When I say "use part of", I'm simply meaning that we will use part of the logic inside your function. Most of the code will be pretty simple to do IMO.

Initially, I'm going to provide you with a "shell" of the functionality and then start piecing things together one section at a time. Some of the functionality that you are wanting to do, I don't know how to do it off the top of my head but I know that it's pretty easy to accomplish. So others will probably need to chime in with help.

I'll be posting the initial shell in a few minutes. I just wanted to get this posted first.
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Another Water change thread this one based on IO Mod floats

Post by lnevo »

I have the libraries scanned by Doxygen. You can browse it here http://www.easte.net/RA/html/

It does help to see what functions are available and see how some functions are implemented.

I do need to update it for 1.0.2, it's still at 1.0.1...
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

Ok. I've got a shell created for you. It's very rudimentary and needs to be tested but should be a good starting point to work with. Feel free to use it or hopefully others can tweak it and modify it to work exactly like you want.

Code: Select all

#include <Salinity.h>
#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

// Ports associated with ATO Ports
// can be multiple ports
byte ATOPorts = 0;
// skimmer port
byte SkimmerPort = Port4;
// return port
byte ReturnPort = Port3;
// sump drain port
byte SumpDrainPort = Port8;
// SaltWater brute pump
byte SWBrutePort = Port7;

void setup()
{
  ReefAngel.Init();
  ATOPorts = Port1 | Port2;  // ports 1 & 2
}

void loop()
{
	// If memory location 10 equals 1
	//		then we start the automatic water change
	// Otherwise we ignore and proceed
	if ( InternalMemory.read(10) == 1 )
	{
		AutoWaterChange();
	}
	ReefAngel.ShowInterface();
}

void AutoWaterChange()
{
	// auto water change mode
	// TODO Clear screen
	//ReefAngel.ClearScreen(DefaultBGColor);
	// check if SW brute is empty, IO Mod Port 2
	if ( isSWBruteEmpty() )
	{
		// Sound Buzzer
		// TODO Clear screen
		//ReefAngel.ClearScreen(DefaultBGColor);
		return;
	}
	
	// turn off ATO ports
	// as a failsafe in case we are in the middle of the ATO topoff
	// TODO this may not be needed at all since we are isolated
	ReefAngel.RelayMaskOff = ~ATOPorts;
	//ReefAngel.Relay.Write();
	
	// turn off the skimmer port
	ReefAngel.Relay.Off(SkimmerPort);
	ReefAngel.Relay.Write();
	
	// wait for 1 minute
	waitForTime(60);
	
	// turn off the return port
	ReefAngel.Relay.Off(ReturnPort);
	ReefAngel.Relay.Write();
	
	// sump actions
	// wait for IO Mod Port 1 to be active
	waitForChannel(1);
	// wait for 1 minute
	waitForTime(60);
	// turn on sump drain
	ReefAngel.Relay.On(SumpDrainPort);
	ReefAngel.Relay.Write();
	// wait for sump empty port active, IO Mod Port 0
	waitForIOChannel(0);
	// turn off sump drain
	ReefAngel.Relay.Off(SumpDrainPort);
	// turn on swbrute pump
	ReefAngel.Relay.On(SWBrutePort);
	ReefAngel.Relay.Write();
	// wait for sump full float switch active, IO Mod Port 1
	waitForIOChannel(1);
	// turn off sw brute pump
	ReefAngel.Relay.Off(SWBrutePort);
	// write handled below
	
	// turn on the return pump
	ReefAngel.Relay.On(ReturnPort);
	ReefAngel.Relay.Write();
	
	// wait for 3 minutes for water levels to stabilize 
	waitForTime(180);
	
	// turn on skimmer
	ReefAngel.Relay.On(SkimmerPort);
	ReefAngel.Relay.Write();
	
	// for for skimmer to stabilize, 2 mintes
	waitForTime(120);
	
	// restore ATO logic and ports
	// TODO this may not be needed at all
	Relay.RelayMaskOff = B11111111;
	ReefAngel.Relay.Write();
	
	// TODO Clear screen
	//ReefAngel.ClearScreen(DefaultBGColor);
}

boolean isSWBruteEmpty()
{
	// TODO complete this function
	// check status of IO Mod Port 2
	// for now, just return false
	return false;
}

void waitForTime(int seconds)
{
	// TODO complete this function
	boolean done = false;
	do
	{
		// wait for specified seconds
		wd_reset();
		// show countdown on screen
		done = true;
	} while ( !done );
	return;
}

void waitForIOChannel(byte channel)
{
	// TODO complete this function
	do
	{
		wd_reset();
		// display something on screen
		// TODO check the IO channel logic
	} while ( ! ReefAngel.IO.GetChannel(channel) );
}
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

Awesome!

thanks Curt for the start. I am spending some time today going through your framework and reading your remarks and trying to get a grasp on it. I may even venture to write a line or two of code. Have to see how well i understand it first. lol. I appreciate the time you have put into this so far.

Thanks lnevo for the link. Now I have a quick reference of at least where to look into the libraries if I need to figure out where/how something works. Probably a good thing i am still running 1.0.1

I'm sure I will be back here with tons of questions on clarification of some things to make sure I "get it"
I have copied the code into an arduino sketch and have started at the top seeing what sense I can make of it.

As I said I'm sure i will have plenty more comments to add later.. lol

Thanks again guys,

Nick
180G FOWLR
20GH QT#1
29G QT#2

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

Another Water change thread this one based on IO Mod floats

Post by lnevo »

That actually made me realize would be a good idea to archive 1.0.1 for those that need in future!
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

There are definitely things that need to be added in to the code I provided. I just didn't have the time to dive into the libraries to refresh my memory on how I did a few things either (drawing the countdown on the screen, reading the IO channel statuses, etc). It should be a good start for you though. I tried to create a couple "helper" functions that make more sense when you read the code (and so you don't have to repeat code). One thing to keep in mind is that you have to "touch" / "reset" the watchdog timer every so many seconds otherwise it restarts the controller. So there may need to be more watchdog resets (wd_reset) called to prevent this from happening (especially in the waitForTime function).
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

Did a little modifying and testing tonight. I took the code supplied above and attempted to compile it. Ran into a handful of compile errors. I think I figured out how to resolve some of the compile errors, others I commented out for now. I wanted to see if I could get any progress down the road. I then copy pasted the pieces of the modified code into my current running config of my controller. I uploaded that code to my controller tonight and attempted some testing. The code I uploaded to my RA+ is as follows.

I kept my additions remarked with the following start and end markers so it can be seen easily where I placed code.

//*****Auto Waterchange Additions Start Here
code
code
//*****Auto Waterchange Additions Ends Here

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <ReefAngel.h>

// Initialize Buzzer variables
byte buzzer=0;
byte overheatflag=0;
byte atoflag=0;
byte iochannel0flag=0;
byte iochannel1flag=0;
byte iochannel2flag=0;
byte iochannel3flag=0;
byte iochannel4flag=0;
byte iochannel5flag=0;

////// Place global variable code below here

//*****Auto Waterchange Additions Start Here
// Ports associated with ATO Ports
// can be multiple ports
byte ATOPorts = 0;
// skimmer port
byte SkimmerPort = Port4;
// return port
byte ReturnPort = Port3;
// sump drain port
byte SumpDrainPort = Port8;
// SaltWater brute pump
byte SWBrutePort = Port7;
//*****Auto Waterchange Additions End Here

////// Place global variable code above here


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = 0;
    ReefAngel.FeedingModePortsE[0] = 0;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port3Bit | Port4Bit;
    ReefAngel.WaterChangePortsE[0] = 0;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    ReefAngel.LightsOnPortsE[0] = Port1Bit | Port2Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port4Bit | Port5Bit | Port6Bit;
    ReefAngel.OverheatShutoffPortsE[0] = 0;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 850 );


    // Ports that are always on
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Box1_Port5 );
    ReefAngel.Relay.On( Box1_Port6 );
    ReefAngel.Relay.On( Box1_Port7 );

    ////// Place additional initialization code below here

    ReefAngel.CustomVar[0]=0;
    ReefAngel.CustomVar[1]=0;    
    ReefAngel.CustomVar[7]=255;   

//*****Auto Waterchange Additions Start Here

    ATOPorts = Port1 | Port2;  // ports 1 & 2
    
//*****Auto Waterchange Additions End Here    

    ////// Place additional initialization code above here
}

void loop()
{
    ReefAngel.StandardFan( Port1,790,820 );
    ReefAngel.StandardATO( Port2,40 );
    ReefAngel.Relay.DelayedOn( Port4,5 );
    ReefAngel.WavemakerRandom( Port5,30,100 );
    ReefAngel.StandardHeater( Port6,750,760 );
    ReefAngel.StandardLights( Box1_Port1,13,0,23,0 );
    ReefAngel.StandardLights( Box1_Port2,13,0,23,0 );
    ReefAngel.StandardHeater( Box1_Port3,750,760 );
    ReefAngel.StandardHeater( Box1_Port4,750,760 );
    ReefAngel.PWM.SetChannel( 0, PWMParabola(14,0,23,59,1,100,1) );
    ReefAngel.PWM.SetChannel( 1, PWMParabola(14,0,23,59,1,100,1) );
    ReefAngel.PWM.SetChannel( 3, PWMSlope(2,0,7,30,0,50,0,0) );
    ReefAngel.PWM.SetChannel( 4, PWMSlope(0,0,14,0,0,50,0,0) );
    overheatflag = InternalMemory.read( Overheat_Exceed_Flag );
    atoflag = InternalMemory.read( ATO_Exceed_Flag );
    iochannel0flag = ReefAngel.IO.GetChannel( 0 );
    iochannel1flag = ReefAngel.IO.GetChannel( 1 );
    iochannel2flag = ReefAngel.IO.GetChannel( 2 );
    iochannel3flag = ReefAngel.IO.GetChannel( 3 );
    iochannel4flag = ReefAngel.IO.GetChannel( 4 );
    iochannel5flag = ReefAngel.IO.GetChannel( 5 );
    buzzer = overheatflag + atoflag + iochannel0flag + iochannel1flag + iochannel2flag + iochannel3flag + iochannel4flag + iochannel5flag;
    if ( buzzer >= 1 ) buzzer = 100;
    ReefAngel.PWM.SetDaylight( buzzer );
    ReefAngel.PWM.SetActinic( buzzer );

    ////// Place your custom code below here

    ReefAngel.CustomVar[0]=InternalMemory.read(ATO_Exceed_Flag);
    ReefAngel.CustomVar[1]=InternalMemory.read(Overheat_Exceed_Flag);
    if ( ReefAngel.CustomVar[0]== 1 )
      {
        ReefAngel.Relay.RelayMaskOff=~(Port4Bit);
      }

 //*****Auto Waterchange Additions Start Here
    // If memory location 10 equals 1
    //      then we start the automatic water change
    // Otherwise we ignore and proceed
    if ( InternalMemory.read(10) == 1 )
    {
      AutoWaterChange();
    }
//*****Auto Waterchange Additions End Here

    ////// Place your custom code above here

    // This should always be the last line
    ReefAngel.Portal( "00Warpig00" );
    ReefAngel.ShowInterface();
}

//*****Auto Waterchange Additions Start Here

void AutoWaterChange()
{
   // auto water change mode
   // TODO Clear screen
   //ReefAngel.ClearScreen(DefaultBGColor);
   // check if SW brute is empty, IO Mod Port 2
   if ( isSWBruteEmpty() )
   {
      // Sound Buzzer
      // TODO Clear screen
      //ReefAngel.ClearScreen(DefaultBGColor);
      return;
   }
   
   // turn off ATO ports
   // as a failsafe in case we are in the middle of the ATO topoff
   // TODO this may not be needed at all since we are isolated
   ReefAngel.Relay.Off(ATOPorts);
   //ReefAngel.Relay.Write();
   
   // turn off the skimmer port
   ReefAngel.Relay.Off(SkimmerPort);
   ReefAngel.Relay.Write();
   
   // wait for 1 minute
   waitForTime(60);
   
   // turn off the return port
   ReefAngel.Relay.Off(ReturnPort);
   ReefAngel.Relay.Write();
   
   // sump actions
   // wait for IO Mod Port 1 to be active
   waitForIOChannel(1);
   //***** WAS waitForChannel(1);
   // wait for 1 minute
   waitForTime(60);
   // turn on sump drain
   ReefAngel.Relay.On(SumpDrainPort);
   ReefAngel.Relay.Write();
   // wait for sump empty port active, IO Mod Port 0
   waitForIOChannel(0);
   // turn off sump drain
   ReefAngel.Relay.Off(SumpDrainPort);
   // turn on swbrute pump
   ReefAngel.Relay.On(SWBrutePort);
   ReefAngel.Relay.Write();
   // wait for sump full float switch active, IO Mod Port 1
   waitForIOChannel(1);
   // turn off sw brute pump
   ReefAngel.Relay.Off(SWBrutePort);
   // write handled below
   
   // turn on the return pump
   ReefAngel.Relay.On(ReturnPort);
   ReefAngel.Relay.Write();
   
   // wait for 3 minutes for water levels to stabilize
   waitForTime(180);
   
   // turn on skimmer
   ReefAngel.Relay.On(SkimmerPort);
   ReefAngel.Relay.Write();
   
   // for for skimmer to stabilize, 2 mintes
   waitForTime(120);
   
   // restore ATO logic and ports
   // TODO this may not be needed at all
//*****Relay.RelayMaskOff = B11111111;
//*****   ReefAngel.Relay.Write();
   
   // TODO Clear screen
   //ReefAngel.ClearScreen(DefaultBGColor);
}

boolean isSWBruteEmpty()
{
   // TODO complete this function
   // check status of IO Mod Port 2
   // for now, just return false
   return false;
}

void waitForTime(int seconds)
{
   // TODO complete this function
   boolean done = false;
   do
   {
      // wait for specified seconds
      int wd_reset();
      // show countdown on screen
      done = true;
   } while ( !done );
   return;
}

void waitForIOChannel(byte channel)
{
   // TODO complete this function
   do
   {
      int wd_reset();
      // display something on screen
      // TODO check the IO channel logic
   } while ( ! ReefAngel.IO.GetChannel(channel) );

}    

//*****Auto Waterchange Additions End Here

void DrawCustomMain()
{
    int x,y;
    char text[10];
    // Dimming Expansion
    x = 15;
    y = 2;
    for ( int a=0;a<6;a++ )
    {
      if ( a>2 ) x = 75;
      if ( a==3 ) y = 2;
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Ch :" );
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+12,y,a );
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+24,y,ReefAngel.PWM.GetChannelValue(a) );
      y += 10;
    }
    pingSerial();

    // I/O Expansion
    byte bkcolor;
    x = 14;
    y = 34;
    for ( int a=0;a<6;a++ )
    {
      ReefAngel.LCD.DrawCircleOutline( x+(a*20),y,4,COLOR_MEDIUMORCHID );
      if ( ReefAngel.IO.GetChannel(a) ) bkcolor=COLOR_WHITE; else bkcolor=COLOR_GRAY;
      ReefAngel.LCD.FillCircle( x+(a*20),y,2,bkcolor );
    }
    pingSerial();

    // Parameters
#if defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 44, ReefAngel.Params,
    ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue() );
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 44, ReefAngel.Params );
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
    pingSerial();

    // Salinity
    ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,15,76, "SAL:" );
    ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,39,76, ReefAngel.Params.Salinity );
    pingSerial();

    // Main Relay Box
    byte TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox( 12, 90, TempRelay );
    pingSerial();

    // Relay Expansion
    TempRelay = ReefAngel.Relay.RelayDataE[0];
    TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
    TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
    ReefAngel.LCD.DrawOutletBox( 12, 104, TempRelay );
    pingSerial();

    // Date and Time
    ReefAngel.LCD.DrawDate( 6, 122 );
    pingSerial();
}

void DrawCustomGraph()
{
}
I placed the controller into water change mode using the menu. I'm not sure the controller even executed any of the code I added.

I have copied below the results of my testing as far as I could go. One thing has become clear to me, I have almost no clue what i'm doing with much of this code. lol

Here are my results so far...

1.Enter water change mode

2.Check IF SW Brute is empty (IO Mod Port 2 Active?)
a.if active inform me of empty brute (chirp buzzer once?) then abort Water change and exit WC mode.
***Does not abort or even seem to notice that IOMod Port 2 is Active

3.disable ATO mode somehow until WC mode is exited (I do WC by draining and refilling SUMP) don't want ATO trying to refill sump during this time. This may already happen in WC mode I'm not sure. If not it needs to. I found this out during my walk through that as soon as my low ato switch detected low water in the sump it kicked on my ato pump to resolve the issue. It didn't know I was draining on purpose. I unplugged both ATO float switches from controller to do this in my mock up after I discovered the issue.
****ATO Mode still active. not surprised at all I kind of expected this. But tested for it just to verify

4.Turn off skimmer (primary relay box port 4)
a.wait a period of time for skimmer to drain (1 minute)

5.Turn off Return pump. (primary relay box port 3)
*** no delay's at all both the return pump and skimmer turn off immediately. Makes me believe the waterchange code I added is not being executed at all. Noticed in my code that i still have the following lines of code

// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port3Bit | Port4Bit;
ReefAngel.WaterChangePortsE[0] = 0;

which I'm guessing are actually whats running.

6.Wait for Sump Full float switch to become active (IO Mod Port 1)
a.then wait an additional minute
b.turn on sump drain pump (primary relay box port 8)
***Sump Drain pump never turns on after IO Mod port 1 becomes active.


Anyone can give me any guidance. It is painfully Obvious I know nothing about c++ coding

Thanks,

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

Give me a chance to look it over more this weekend. I can look at it on Sunday afternoon / evening more.
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

No problem Curt. thanks again for your help. I'm also going to try to dig in a little bit more and see if I can figure some stuff out.

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

I looked at the code again briefly and have a few comments for your comments. I'm just going to keep the same numbers and post a reply:

2. the "int wd_reset();" line shouldn't have "int" in front of it. If it fails to compile then I may have used the wrong function call or the watchdog timer is not being included. I will have to look into that one.
As far as it not recognizing the IOmod port 2, the function isSWBruteEmpty() does absolutely nothing currently. All it does is just return false right now. I wrote in comments inside the function that it needs to check the status of it but it has not been completed. So this function still needs to be written.

3. I didn't know if the ATO ports were a single port or multiple ports. I have it set right now for a single port turning off/on. This will have to be changed then.

4 & 5. The waitForTime function does not wait at all. It simply runs and exits. The delay still needs to be completed.

6. The sump drain will not appear to have turned on and off because it happens so fast due to the same reason for 4&5.

Ok, those were just some comments for the reasons you are experiencing what you were experiencing.
Here's an improved waitForTime function

Code: Select all

// this goes at the top inside the global variable code with the other auto waterchange variables
// Timer for countdowns
TimerClass tm;

// function
void waitForTime(int seconds)
{
    bool done = false;
    tm.SetInterval(seconds);
    tm.Start();
    int t = tm.Trigger - now();
    do
    {
        // wait for specified seconds
        if ( (t >= 0) && ! tm.isTriggered() )
        {
            // TODO finish countdown on screen
            // show countdown on screen
	        //LCD.Clear(DefaultBGColor,60+(intlength(t)*5),100,100,108);
    	    //LCD.DrawText(DefaultFGColor,DefaultBGColor,60,100,t);
            wdt_reset();
            delay(200);
        }
        else
        {
            done = true;
        }
    } while ( !done );
    return;
}
More to come later, but this is just another piece of the puzzle.
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

binder wrote:I looked at the code again briefly and have a few comments for your comments. I'm just going to keep the same numbers and post a reply:

2. the "int wd_reset();" line shouldn't have "int" in front of it. If it fails to compile then I may have used the wrong function call or the watchdog timer is not being included. I will have to look into that one.
As far as it not recognizing the IOmod port 2, the function isSWBruteEmpty() does absolutely nothing currently. All it does is just return false right now. I wrote in comments inside the function that it needs to check the status of it but it has not been completed. So this function still needs to be written.
The int wd_reset() was my lack of coding prowess. Grabbing at straws to get it to compile.

binder wrote: 3. I didn't know if the ATO ports were a single port or multiple ports. I have it set right now for a single port turning off/on. This will have to be changed then.
As for my setup I am using the Dual ATO for my topoff and both ATO floats are plugged into the controller directly and configured in the method outlined in the Reef Angel manual. The IO mod has the additional 6 float switches that deal strictly with empty\full conditions in my sump my RO Brute and my SW Brute.

I've been studying up and things are starting to make more sense to me as I watch endless hours of youtube arduino tutorials, most of which deal mostly with hooking up gadgets and not as much on the coding structure. Most of these tutorials seem to assume you already know how to code.
binder wrote: 4 & 5. The waitForTime function does not wait at all. It simply runs and exits. The delay still needs to be completed.
Thanks for working on the WaitForTime function. :) I really appreciate your efforts. Hopefully soon i will be able to help myself with some of this.
binder wrote: 6. The sump drain will not appear to have turned on and off because it happens so fast due to the same reason for 4&5.

Ok, those were just some comments for the reasons you are experiencing what you were experiencing.
Here's an improved waitForTime function
This may or may not have been the issue with the sump drain pump. I had the relay box sitting on the workbench when i tested and didn't even hear the slightest peep out of any relay when this portion of the code would have been reached.
binder wrote: More to come later, but this is just another piece of the puzzle.
Awesome! thanks.

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

I think I have the function completed. I do not have any of the screen updating / changing but the functionality should be working now.

Code: Select all


#include <Salinity.h>
#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

// Ports associated with ATO Ports
// can be multiple ports
byte ATOPorts = 0;
// skimmer port
byte SkimmerPort = Port4;
// return port
byte ReturnPort = Port3;
// sump drain port
byte SumpDrainPort = Port8;
// SaltWater brute pump
byte SWBrutePort = Port7;
// Timer for countdowns
TimerClass tm;

void setup()
{
  ReefAngel.Init();
  ATOPorts = Port1 | Port2;  // ports 1 & 2
}

void loop()
{
   // If memory location 10 equals 1
   //      then we start the automatic water change
   // Otherwise we ignore and proceed
   if ( InternalMemory.read(10) == 1 )
   {
      AutoWaterChange();
   }
   ReefAngel.ShowInterface();
}

void AutoWaterChange()
{
   // auto water change mode
   // TODO Clear screen
   //ReefAngel.ClearScreen(DefaultBGColor);
   // check if SW brute is empty, IO Mod Port 2
   if ( isSWBruteEmpty() )
   {
        // Sound Buzzer
        // TODO Clear screen
        //ReefAngel.ClearScreen(DefaultBGColor);
        ReefAngel.PWM.SetDaylight( 100 );
        ReefAngel.PWM.SetActinic( 100 );
        return;
   }
   
   // turn off ATO ports
   // as a failsafe in case we are in the middle of the ATO topoff
   // TODO this may not be needed at all since we are isolated
   ReefAngel.RelayMaskOff = ~ATOPorts;
   //ReefAngel.Relay.Write();
   
   // turn off the skimmer port
   ReefAngel.Relay.Off(SkimmerPort);
   ReefAngel.Relay.Write();
   
   // wait for 1 minute
   waitForTime(60);
   
   // turn off the return port
   ReefAngel.Relay.Off(ReturnPort);
   ReefAngel.Relay.Write();
   
   // sump actions
   // wait for IO Mod Port 1 to be active
   waitForChannel(1);
   // wait for 1 minute
   waitForTime(60);
   // turn on sump drain
   ReefAngel.Relay.On(SumpDrainPort);
   ReefAngel.Relay.Write();
   // wait for sump empty port active, IO Mod Port 0
   waitForIOChannel(0);
   // turn off sump drain
   ReefAngel.Relay.Off(SumpDrainPort);
   // turn on swbrute pump
   ReefAngel.Relay.On(SWBrutePort);
   ReefAngel.Relay.Write();
   // wait for sump full float switch active, IO Mod Port 1
   waitForIOChannel(1);
   // turn off sw brute pump
   ReefAngel.Relay.Off(SWBrutePort);
   // write handled below
   
   // turn on the return pump
   ReefAngel.Relay.On(ReturnPort);
   ReefAngel.Relay.Write();
   
   // wait for 3 minutes for water levels to stabilize 
   waitForTime(180);
   
   // turn on skimmer
   ReefAngel.Relay.On(SkimmerPort);
   ReefAngel.Relay.Write();
   
   // for for skimmer to stabilize, 2 mintes
   waitForTime(120);
   
   // restore ATO logic and ports
   // TODO this may not be needed at all
   Relay.RelayMaskOff = B11111111;
   ReefAngel.Relay.Write();
   
   // TODO Clear screen
   //ReefAngel.ClearScreen(DefaultBGColor);
}

bool isSWBruteEmpty()
{
    // check status of IO Mod Port 2
    if ( ReefAngel.IO.GetChannel(2) )
        return true;
    return false;
}

void waitForTime(int seconds)
{
    bool done = false;
    tm.SetInterval(seconds);
    tm.Start();
    int t = tm.Trigger - now();
    do
    {
        // wait for specified seconds
        if ( (t >= 0) && ! tm.isTriggered() )
        {
            // TODO finish countdown on screen
            // show countdown on screen
           //LCD.Clear(DefaultBGColor,60+(intlength(t)*5),100,100,108);
           //LCD.DrawText(DefaultFGColor,DefaultBGColor,60,100,t);
            wdt_reset();
            delay(200);
        }
        else
        {
            done = true;
        }
    } while ( !done );
    return;
}

void waitForIOChannel(byte channel)
{
    // TODO complete this function
    do
    {
        wdt_reset();
        // display something on screen
        delay(200);
        // TODO check the IO channel logic
    } while ( ! ReefAngel.IO.GetChannel(channel) );
}
You will have to check the status of the waitForIOChannel function. It is currently set that when GetChannel returns 1, the channel is ready. This may be the exact opposite of what you want. I'm thinking that because of your line:

Code: Select all

    buzzer = overheatflag + atoflag + iochannel0flag + iochannel1flag + iochannel2flag + iochannel3flag + iochannel4flag + iochannel5flag;
    if ( buzzer >= 1 ) buzzer = 100;
and when any of the channels report 1, you trigger the buzzer.
If it I have the logic backwards, then you will need to remove the exclamation point to flip the logic in the waitForIOChannel function.

Also, the ATOPorts being shutoff are the actual relay ports that are getting turned off. So if you have one ato pump plugged in, then you will only need one port. Regardless of if you are using the dual ato ports, you probably only have 1 ato pump.
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

binder wrote:I think I have the function completed. I do not have any of the screen updating / changing but the functionality should be working now.
This looks Awesome! thanks so much. Looking over the code I seem to be making sense of most of it. :) I am going to do some copy/paste into my current config and hopefully do some testing tomorrow.
binder wrote: You will have to check the status of the waitForIOChannel function. It is currently set that when GetChannel returns 1, the channel is ready. This may be the exact opposite of what you want.

...and when any of the channels report 1, you trigger the buzzer.
If it I have the logic backwards, then you will need to remove the exclamation point to flip the logic in the waitForIOChannel function.
I have all my floats set so when they are in the inactive (green dot in the portal) things are normal. I treat the red dot in the portal as a red flag of sorts. IE Sump\topoff\Saltwater brute are NOT empty or NOT full but between as in the normal operating state. So as long as Active =1 and Inactive=0 I think this is correct. :)
binder wrote: I'm thinking that because of your line:

Code: Select all

    buzzer = overheatflag + atoflag + iochannel0flag + iochannel1flag + iochannel2flag + iochannel3flag + iochannel4flag + iochannel5flag;
    if ( buzzer >= 1 ) buzzer = 100;
Actually I am glad you brought this specific code up. I need to look into this a bit because my buzzer is in an always on state right now and was unplugged long ago. Been trying to deal with the other issues I'd like to get ironed out first. So I will be looking into the buzzer coding soon. I also want to make the buzzer more of a chirp every x seconds instead of a constant tone but that's a project for later...

binder wrote: Also, the ATOPorts being shutoff are the actual relay ports that are getting turned off. So if you have one ato pump plugged in, then you will only need one port. Regardless of if you are using the dual ato ports, you probably only have 1 ato pump.
Makes perfect sense to just mask "off" the ATO Pump port during the water change. Then return to normal state when finished. :)

I cant wait to test this out tomorrow after work. :D

Thanks Curt

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

I Did some preliminary testing tonight and still didn't get very far through a simulated water change.

Here is the code I tested with.

NOTE: I am still not sure I am making it into this newly added water change code at all. I added a byte variable "WCMode" set it to "1" during normal mode and set that variable to several different values from 50-255 in various places within the water change and other functions involved in a water change in the code below so I could query the controller with the android app during my testing. I NEVER saw this variable change to anything other than the "1" I set it to during normal mode. makes me wonder if I'm even getting into my new code at all.

So I started water change mode from the controller screen and my relay box port5 (circulation pumps),
port6 (heater) and port8 (sump drain pump) were all immediately and unexpectedly masked off. The skimmer (relay Port4) and Return pump (relay port3) never masked off and stayed running. IO Mod port 2 (SW Brute Empty) never aborted the water change when active during WC start. The controller just sat with "Water change" on the screen until I pulled the plug and rebooted it. Maybe it exited WC mode but the screen didnt update. I'm not sure. I also tested with IO Mod port 2 inactive where the code should have turned on the sump drain pump (relay port8) and pumped until IO Mod Port 0 became active. The pump never turned on.

I am going to inspect the code a bit closer but I am still not convinced this new WC code is being run at all.

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

// Initialize Buzzer variables
byte buzzer=0;
byte overheatflag=0;
byte atoflag=0;
byte iochannel0flag=0;
byte iochannel1flag=0;
byte iochannel2flag=0;
byte iochannel3flag=0;
byte iochannel4flag=0;
byte iochannel5flag=0;

////// Place global variable code below here

//*****Begin WC Additions

//Is waterchange active
byte WCMode = 1;
// Ports associated with ATO Ports
// can be multiple ports
byte ATOPorts = 0;
// skimmer port
byte SkimmerPort = Port4;
// return port
byte ReturnPort = Port3;
// sump drain port
byte SumpDrainPort = Port8;
// SaltWater brute pump
byte SWBrutePort = Port7;
// Timer for countdowns
TimerClass tm;

//*****End WC Additions

////// Place global variable code above here


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = 0;
    ReefAngel.FeedingModePortsE[0] = 0;
    // Ports toggled in Water Change Mode
//*****WC    ReefAngel.WaterChangePorts = Port3Bit | Port4Bit;
//*****WC    ReefAngel.WaterChangePortsE[0] = 0;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    ReefAngel.LightsOnPortsE[0] = Port1Bit | Port2Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port4Bit | Port5Bit | Port6Bit;
    ReefAngel.OverheatShutoffPortsE[0] = 0;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 850 );


    // Ports that are always on
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Box1_Port5 );
    ReefAngel.Relay.On( Box1_Port6 );
    ReefAngel.Relay.On( Box1_Port7 );

    ////// Place additional initialization code below here
  
    //*****Begin WC Additions

    ATOPorts = Port1 | Port2;  // ports 1 & 2

    //*****End WC Additions

    ReefAngel.CustomVar[0]=0;
    ReefAngel.CustomVar[1]=0;
    ReefAngel.CustomVar[2]=0;
    ReefAngel.CustomVar[3]=0;
    ReefAngel.CustomVar[4]=0;
    ReefAngel.CustomVar[5]=0;
    ReefAngel.CustomVar[6]=0;   
    ReefAngel.CustomVar[7]=255;   


    ////// Place additional initialization code above here
}

void loop()
{
    ReefAngel.StandardFan( Port1,790,820 );
    ReefAngel.StandardATO( Port2,40 );
    ReefAngel.Relay.DelayedOn( Port4,1 );
//    ReefAngel.WavemakerRandom( Port5,30,100 );
    ReefAngel.StandardHeater( Port6,750,760 );
    ReefAngel.StandardLights( Box1_Port1,13,0,23,0 );
    ReefAngel.StandardLights( Box1_Port2,13,0,23,0 );
    ReefAngel.StandardHeater( Box1_Port3,750,760 );
    ReefAngel.StandardHeater( Box1_Port4,750,760 );
    ReefAngel.PWM.SetChannel( 0, PWMParabola(14,0,23,59,1,100,1) );
    ReefAngel.PWM.SetChannel( 1, PWMParabola(14,0,23,59,1,100,1) );
    ReefAngel.PWM.SetChannel( 3, PWMSlope(2,0,7,30,0,50,0,0) );
    ReefAngel.PWM.SetChannel( 4, PWMSlope(0,0,14,0,0,50,0,0) );
    overheatflag = InternalMemory.read( Overheat_Exceed_Flag );
    atoflag = InternalMemory.read( ATO_Exceed_Flag );
    iochannel0flag = ! ReefAngel.IO.GetChannel( 0 );
    iochannel1flag = ! ReefAngel.IO.GetChannel( 1 );
    iochannel2flag = ! ReefAngel.IO.GetChannel( 2 );
    iochannel3flag = ! ReefAngel.IO.GetChannel( 3 );
    iochannel4flag = ! ReefAngel.IO.GetChannel( 4 );
    iochannel5flag = ! ReefAngel.IO.GetChannel( 5 );
    buzzer = overheatflag + atoflag + iochannel0flag + iochannel1flag + iochannel2flag + iochannel3flag + iochannel4flag + iochannel5flag;
    if ( buzzer >= 1 ) buzzer = 40;
    ReefAngel.PWM.SetDaylight( buzzer );
    ReefAngel.PWM.SetActinic( buzzer );

    ////// Place your custom code below here

    ReefAngel.CustomVar[0]=InternalMemory.read(ATO_Exceed_Flag);
    ReefAngel.CustomVar[1]=InternalMemory.read(Overheat_Exceed_Flag);
    ReefAngel.CustomVar[2]=buzzer;
    ReefAngel.CustomVar[3]=WCMode;
    ReefAngel.CustomVar[4]=0;
    ReefAngel.CustomVar[5]=0;
    ReefAngel.CustomVar[6]=0;   
    ReefAngel.CustomVar[7]=255; 
    
    if ( ReefAngel.CustomVar[0]== 1 )
      {
        ReefAngel.Relay.RelayMaskOff=~(Port4Bit);
      }

    //*****Begin WC Additions

    // If memory location 10 equals 1
    //      then we start the automatic water change
    // Otherwise we ignore and proceed
    if ( InternalMemory.read(10) == 1 )
      {
        WCMode = 255;
        ReefAngel.CustomVar[3]=WCMode;       
        AutoWaterChange();
      }
    
    //*****End WC Additions

    ////// Place your custom code above here

    // This should always be the last line
    ReefAngel.Portal( "00Warpig00" );
    ReefAngel.ShowInterface();
}


//*****Begin WC Additions

void AutoWaterChange()
{

    WCMode = 254;
    ReefAngel.CustomVar[3]=WCMode;
    // auto water change mode
    // TODO Clear screen
    //ReefAngel.ClearScreen(DefaultBGColor);
    // check if SW brute is empty, IO Mod Port 2
    if ( isSWBruteEmpty() )
      {
        WCMode = 250;
        ReefAngel.CustomVar[3]=WCMode;
        // Sound Buzzer
        // TODO Clear screen
        //ReefAngel.ClearScreen(DefaultBGColor);
        ReefAngel.PWM.SetDaylight( 90 );
        ReefAngel.PWM.SetActinic( 90 );
        return;
      }
   
    // turn off ATO ports
    // as a failsafe in case we are in the middle of the ATO topoff
    // TODO this may not be needed at all since we are isolated
    ReefAngel.Relay.RelayMaskOff = ~ATOPorts;

    WCMode = 245;
    ReefAngel.CustomVar[3]=WCMode;
    //ReefAngel.Relay.Write();
   
    WCMode = 240;
    ReefAngel.CustomVar[3]=WCMode;
    // turn off the skimmer port
    ReefAngel.Relay.Off(SkimmerPort);
    ReefAngel.Relay.Write();
   
    // wait for 1 minute
    waitForTime(60);
   
    // turn off the return port
    WCMode = 235;
    ReefAngel.CustomVar[3]=WCMode;
    ReefAngel.Relay.Off(ReturnPort);
    ReefAngel.Relay.Write();
   
    // sump actions
    // wait for IO Mod Port 1 to be active
    waitForIOChannel(1);
    // wait for 1 minute
    waitForTime(60);
    // turn on sump drain
    WCMode = 230;
    ReefAngel.CustomVar[3]=WCMode;
    ReefAngel.Relay.On(SumpDrainPort);
    ReefAngel.Relay.Write();
    WCMode = 225;
    ReefAngel.CustomVar[3]=WCMode;
    // wait for sump empty port active, IO Mod Port 0
    waitForIOChannel(0);
    // turn off sump drain
    WCMode = 220;
    ReefAngel.CustomVar[3]=WCMode;
    ReefAngel.Relay.Off(SumpDrainPort);
    // turn on swbrute pump
    ReefAngel.Relay.On(SWBrutePort);
    ReefAngel.Relay.Write();
    WCMode = 215;
    ReefAngel.CustomVar[3]=WCMode;
    // wait for sump full float switch active, IO Mod Port 1
    waitForIOChannel(1);
    // turn off sw brute pump
    WCMode = 210;
    ReefAngel.CustomVar[3]=WCMode;
    ReefAngel.Relay.Off(SWBrutePort);
    // write handled below
   
    // turn on the return pump
    ReefAngel.Relay.On(ReturnPort);
    ReefAngel.Relay.Write();
    WCMode = 205;
    ReefAngel.CustomVar[3]=WCMode;   
    // wait for 3 minutes for water levels to stabilize
    waitForTime(180);
   
    // turn on skimmer
    WCMode = 200;
    ReefAngel.CustomVar[3]=WCMode;
    ReefAngel.Relay.On(SkimmerPort);
    ReefAngel.Relay.Write();
    WCMode = 195;
    ReefAngel.CustomVar[3]=WCMode;   
    // for for skimmer to stabilize, 2 mintes
    waitForTime(120);
   
    // restore ATO logic and ports
    // TODO this may not be needed at all
    WCMode = 190;
    ReefAngel.CustomVar[3]=WCMode;
    ReefAngel.Relay.RelayMaskOff = B11111111;
    ReefAngel.Relay.Write();
    WCMode = 185;
    ReefAngel.CustomVar[3]=WCMode;   
    // TODO Clear screen
    //ReefAngel.ClearScreen(DefaultBGColor);
}

bool isSWBruteEmpty()
{
    WCMode = 150;
    ReefAngel.CustomVar[3]=WCMode;
  // check status of IO Mod Port 2
    if ( ReefAngel.IO.GetChannel(2) )
      return true;
    return false;
}

void waitForTime(int seconds)
{
    WCMode = 60;
    ReefAngel.CustomVar[3]=WCMode;
    bool done = false;
    tm.SetInterval(seconds);
    tm.Start();
    int t = tm.Trigger - now();
    do
    {
      // wait for specified seconds
      if ( (t >= 0) && ! tm.IsTriggered() )
        {
          // TODO finish countdown on screen
          // show countdown on screen
          //LCD.Clear(DefaultBGColor,60+(intlength(t)*5),100,100,108);
          //LCD.DrawText(DefaultFGColor,DefaultBGColor,60,100,t);
          wdt_reset();
          delay(200);
        }
        else
        {
          done = true;
        }
    } while ( !done );
    return;
}

void waitForIOChannel(byte channel)
{
    WCMode = 100;
    ReefAngel.CustomVar[3]=WCMode;
    // TODO complete this function
    do
    {
      wdt_reset();
      // display something on screen
      delay(200);
      // TODO check the IO channel logic
    } while ( ! ReefAngel.IO.GetChannel(channel) );
    WCMode = 99;
    ReefAngel.CustomVar[3]=WCMode;
}

//*****End WC Additions


void DrawCustomMain()
{
    int x,y;
    char text[10];
    // Dimming Expansion
    x = 15;
    y = 2;
    for ( int a=0;a<6;a++ )
    {
      if ( a>2 ) x = 75;
      if ( a==3 ) y = 2;
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Ch :" );
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+12,y,a );
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+24,y,ReefAngel.PWM.GetChannelValue(a) );
      y += 10;
    }
    pingSerial();

    // I/O Expansion
    byte bkcolor;
    x = 14;
    y = 34;
    for ( int a=0;a<6;a++ )
    {
      ReefAngel.LCD.DrawCircleOutline( x+(a*20),y,4,COLOR_MEDIUMORCHID );
      if ( ReefAngel.IO.GetChannel(a) ) bkcolor=COLOR_WHITE; else bkcolor=COLOR_GRAY;
      ReefAngel.LCD.FillCircle( x+(a*20),y,2,bkcolor );
    }
    pingSerial();

    // Parameters
#if defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 44, ReefAngel.Params,
    ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue() );
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 44, ReefAngel.Params );
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
    pingSerial();

    // Salinity
    ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,15,76, "SAL:" );
    ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,39,76, ReefAngel.Params.Salinity );
    pingSerial();

    // Main Relay Box
    byte TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox( 12, 90, TempRelay );
    pingSerial();

    // Relay Expansion
    TempRelay = ReefAngel.Relay.RelayDataE[0];
    TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
    TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
    ReefAngel.LCD.DrawOutletBox( 12, 104, TempRelay );
    pingSerial();

    // Date and Time
    ReefAngel.LCD.DrawDate( 6, 122 );
    pingSerial();
}

void DrawCustomGraph()
{
}
180G FOWLR
20GH QT#1
29G QT#2

Image
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

ok. well i will look at it this weekend and try loading it on to one of my controllers to test. i can't check the io mod ports because i don't have one but i can check the other stuff.
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

binder wrote:ok. well i will look at it this weekend and try loading it on to one of my controllers to test. i can't check the io mod ports because i don't have one but i can check the other stuff.

Made HUGE progress on this tonight. Your Code was pretty much perfect Curt. I'm probably still going to have a few questions but this seems to be working at about 95% of what I was hoping for. After poking around some and LOTS of experimenting turns out my hunch was correct and none of this code was being executed. I think it is because your code check memory location 10 for water change mode and when I set up my RA+ using the Reef Angel Wizard I chose NOT to use the "Memory" features and code everything because I'm such a newb at this stuff. So I searched around on the site and found the other way of starting water change mode. I remarked out your line

Code: Select all


if ( InternalMemory.read(10) == 1 )

and inserted the line

Code: Select all


if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE)

in it's place. I also placed several text draws to the screen to give me updates about where in the code things were at. It took a bit of tweaking but I'm happy to report I'm about 95% happy with my results so far. :D

I am sure I will have some more questions before this is all said and done but it's looking GREAT so far!

Now Off to get some sleep. My eyes are burning... lol

Thanks again for all your help,

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

thats great. glad you got things working for the most part. as for entering the mode, you still can use the internal memory even though you are not using it anywhere else provided you have a wifi adapter. you simply use one of the apps to set the value at memory location 10 and it would start. of course now there's one thing that i need to add to the function and that is to clear out the memory location when the function exits.

regardless, what you changed it to will work for you and allow you to trigger it from the menu. you just need to exit water change mode when that function exits. we can work on that more later.

good job! :smile:
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Another Water change thread this one based on IO Mod flo

Post by rimai »

Cool!!!
Roberto.
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

binder wrote:thats great. glad you got things working for the most part. as for entering the mode, you still can use the internal memory even though you are not using it anywhere else provided you have a wifi adapter. you simply use one of the apps to set the value at memory location 10 and it would start. of course now there's one thing that i need to add to the function and that is to clear out the memory location when the function exits.

regardless, what you changed it to will work for you and allow you to trigger it from the menu. you just need to exit water change mode when that function exits. we can work on that more later.

good job! :smile:
fooled around with this toady and using the internal memory for me does not work.

my "InternalMemory.read(10)" ALWAYS = 255. Never goes to any other value that I can tell.

I've got the water change code working well and fully tested. I added a bunch of screen draws along the road so the controller tells me what is going on at any moment during the water change. I did notice that my controller stops responding to my wifi mod and any refreshes over the android app to see what is going on during the process with the relay ports IO ports etc. All queries to the controller during water change are met with a XML Parser error. When the mode is finished I need to press the joystick button to return to the main menu and they wifi can communicate again. not a huge problem since I am planning fully attended waterchanges for the indefinite future but it would be cool to still have the wifi mod working during the water change.

I also would like to change my buzzer function to have the buzzer beep/chirp for a quarter of a second every two minutes or so instead of just wailing about constantly. any ideas on how to do this would be welcomed.

here is my current test code in case anyone is interested.

Nick

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

// Initialize Buzzer variables
byte buzzer=0;
byte overheatflag=0;
byte atoflag=0;
byte iochannel0flag=0;
byte iochannel1flag=0;
byte iochannel2flag=0;
byte iochannel3flag=0;
byte iochannel4flag=0;
byte iochannel5flag=0;

////// Place global variable code below here

//*****Begin WC Additions

// Ports associated with ATO Ports
// can be multiple ports
byte ATOPorts = 0;
// skimmer port
byte SkimmerPort = Port4;
// return port
byte ReturnPort = Port3;
// sump drain port
byte SumpDrainPort = Port8;
// SaltWater brute pump
byte SWBrutePort = Port7;
// Timer for countdowns
TimerClass tm;

//*****End WC Additions

////// Place global variable code above here


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = 0;
    ReefAngel.FeedingModePortsE[0] = 0;
    // Ports toggled in Water Change Mode
//*****WC    ReefAngel.WaterChangePorts = Port3Bit | Port4Bit;
//*****WC    ReefAngel.WaterChangePortsE[0] = 0;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    ReefAngel.LightsOnPortsE[0] = Port1Bit | Port2Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port4Bit | Port5Bit | Port6Bit;
    ReefAngel.OverheatShutoffPortsE[0] = 0;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 850 );


    // Ports that are always on
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Box1_Port5 );
    ReefAngel.Relay.On( Box1_Port6 );
    ReefAngel.Relay.On( Box1_Port7 );

    ////// Place additional initialization code below here
  
    //*****Begin WC Additions

//    ATOPorts = Port1 | Port2;  // ports 1 & 2

    //*****End WC Additions

    ReefAngel.CustomVar[0]=0;
    ReefAngel.CustomVar[1]=0;
    ReefAngel.CustomVar[2]=0;
    ReefAngel.CustomVar[3]=0;
    ReefAngel.CustomVar[4]=0;
    ReefAngel.CustomVar[5]=0;
    ReefAngel.CustomVar[6]=0;   
    ReefAngel.CustomVar[7]=255;   


    ////// Place additional initialization code above here
}

void loop()
{
    ReefAngel.StandardFan( Port1,790,820 );
    ReefAngel.StandardATO( Port2,40 );
    ReefAngel.Relay.DelayedOn( Port4,1 );
//    ReefAngel.WavemakerRandom( Port5,30,100 );
    ReefAngel.StandardHeater( Port6,750,760 );
    ReefAngel.StandardLights( Box1_Port1,13,0,23,0 );
    ReefAngel.StandardLights( Box1_Port2,13,0,23,0 );
    ReefAngel.StandardHeater( Box1_Port3,750,760 );
    ReefAngel.StandardHeater( Box1_Port4,750,760 );
    ReefAngel.PWM.SetChannel( 0, PWMParabola(14,0,23,59,1,100,1) );
    ReefAngel.PWM.SetChannel( 1, PWMParabola(14,0,23,59,1,100,1) );
    ReefAngel.PWM.SetChannel( 3, PWMSlope(2,0,7,30,0,50,0,0) );
    ReefAngel.PWM.SetChannel( 4, PWMSlope(0,0,14,0,0,50,0,0) );
    overheatflag = InternalMemory.read( Overheat_Exceed_Flag );
    atoflag = InternalMemory.read( ATO_Exceed_Flag );
    iochannel0flag = ! ReefAngel.IO.GetChannel( 0 );
    iochannel1flag = ! ReefAngel.IO.GetChannel( 1 );
    iochannel2flag = ! ReefAngel.IO.GetChannel( 2 );
    iochannel3flag = ! ReefAngel.IO.GetChannel( 3 );
    iochannel4flag = ! ReefAngel.IO.GetChannel( 4 );
    iochannel5flag = ! ReefAngel.IO.GetChannel( 5 );
    buzzer = overheatflag + atoflag + iochannel0flag + iochannel1flag + iochannel2flag + iochannel3flag + iochannel4flag + iochannel5flag;
    if ( buzzer >= 1 ) buzzer = 40;
    ReefAngel.PWM.SetDaylight( buzzer );
    ReefAngel.PWM.SetActinic( buzzer );

    ////// Place your custom code below here

    ReefAngel.CustomVar[0]=InternalMemory.read(ATO_Exceed_Flag);
    ReefAngel.CustomVar[1]=InternalMemory.read(Overheat_Exceed_Flag);
    ReefAngel.CustomVar[2]=InternalMemory.read(10);
    ReefAngel.CustomVar[3]=0;
    ReefAngel.CustomVar[4]=0;
    ReefAngel.CustomVar[5]=0;
    ReefAngel.CustomVar[6]=0;   
    ReefAngel.CustomVar[7]=255; 
    
    if ( ReefAngel.CustomVar[0]== 1 )
      {
        ReefAngel.Relay.RelayMaskOff=~(Port4Bit);
      }

    //*****Begin WC Additions

    // If memory location 10 equals 1
    //      then we start the automatic water change
    // Otherwise we ignore and proceed
    if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE)
//    if ( InternalMemory.read(10) == 1 )
      {
        AutoWaterChange();
      }
    
    //*****End WC Additions

    ////// Place your custom code above here

    // This should always be the last line
    ReefAngel.Portal( "00Warpig00" );
    ReefAngel.ShowInterface();
}


//*****Begin WC Additions

void AutoWaterChange()
{
    // auto water change mode

    //display internal memory location 10 water change mode    
//    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 50, "                      ");
//    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 50, "internal Memory 10");
//    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 60, ReefAngel.CustomVar[2] ); waitForTime(3);        
    
    // Display Starting Water Change"
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Starting Water Change"); waitForTime(3);

    // Check Saltwater BRUTE for sufficient saltwater on IO Module Port2
    if ( isSWBruteEmpty() )
      {
        ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
        ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Not Enough Saltwater"); waitForTime(3);

        //Abort Water Change if insufficient saltwater
        ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
        return;
      }
   
    //Display Disabling ATO Pump
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");    
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Disabling ATO Pump"); waitForTime(3);

    // turn off ATO pump port to prevent ATO from trying to fill a sump being drained intentionally
//    ReefAngel.Relay.RelayMaskOff = ~ATOPorts;
    ReefAngel.Relay.RelayMaskOff=~(Port2Bit);
    //ReefAngel.Relay.Write();
   
    //Display Stopping Skimmer
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Stopping Skimmer"); waitForTime(3);

    // turn off the skimmer port
    ReefAngel.Relay.Off(SkimmerPort);
    ReefAngel.Relay.Write();
    
    //Display Skimmer Draining
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Skimmer Draining"); waitForTime(3);    

    // wait for 1 minute
    waitForTime(60);

    //Display Skimmer Done Draining
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Skimmer Done Draining"); waitForTime(3);
    
    //display Stopping Return Pump
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Stopping Return Pump"); waitForTime(3);

    //Stop Return Pump
    ReefAngel.Relay.Off(ReturnPort);
    ReefAngel.Relay.Write();
   
    //Display Draining To Sump
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Draining To Sump"); waitForTime(3);

    //display Sump Filling
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Filling"); waitForTime(3);

    // wait for IO Mod Port 1 to be active
    waitForIOChannel(1);

    //display Sump Is Full
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Is Full"); waitForTime(3);

    //Display Sump Settling
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Settling"); waitForTime(3);

    // wait for sump to settle
    waitForTime(30);
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Settled"); waitForTime(3);

    // display Draining Sump
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Start Draining Sump"); waitForTime(3);

    //turn on sump drain pump
    ReefAngel.Relay.On(SumpDrainPort);
    ReefAngel.Relay.Write();

    //display Sump Draining
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Draining"); waitForTime(3);

    // wait for sump empty port active, IO Mod Port 0
    waitForIOChannel(0);
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Is Empty"); waitForTime(3);

    //display Stopping Sump Draining
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Stopping Sump Drain"); waitForTime(3);

    // turn off sump drain
    ReefAngel.Relay.Off(SumpDrainPort);
    ReefAngel.Relay.Write();

    //Display Sump Settling
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Settling"); waitForTime(3);

    // wait for sump to settle
    waitForTime(30);

    //display Sump Settled
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Settled"); waitForTime(3);

    //display Starting Saltwater Pump
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Start Saltwater Pump"); waitForTime(3);
 
    //turn on Saltwater Pump
    ReefAngel.Relay.On(SWBrutePort);
    ReefAngel.Relay.Write();

    //display Saltwater Pumping
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Saltwater Pumping"); waitForTime(3);

    // wait for sump full float switch active, IO Mod Port 1
    waitForIOChannel(1);

    //display Stop Saltwater Pump
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Stop Saltwater Pump"); waitForTime(3);

    // turn off sw brute pump
    ReefAngel.Relay.Off(SWBrutePort);
    ReefAngel.Relay.Write();    

    //diasplay Sump is Full
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Is Full"); waitForTime(3);

    //Display Sump Settling
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Settling"); waitForTime(3);

    // wait for sump to settle
    waitForTime(30);

    //display Sump Settled
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Sump Settled"); waitForTime(3);
   
    //display Starting Return Pump
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Starting Return Pump"); waitForTime(3);

    // turn on return pump
    ReefAngel.Relay.On(ReturnPort);
    ReefAngel.Relay.Write();

    //display Return Pump Started
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Return Pump Started"); waitForTime(3);
 
    //display Normalizing Waterlevel
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Normalizing Waterlevel"); waitForTime(3);

    //waiting 2 minutes for waterlevel to normalize
    waitForTime(120);
   
    //display Starting Skimer
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Starting Skimmer"); waitForTime(3);

    //turn on skimmer
    ReefAngel.Relay.On(SkimmerPort);
    ReefAngel.Relay.Write();

    //display Normalizing Skimmer
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Normalizing Skimmer"); waitForTime(3);

    //wait for 2 minutes for skimmer to normalize
    waitForTime(120);

    //display Skimmer Normalized
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Skimmer Normalized"); waitForTime(3);

    //display Enabling ATO Pump
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Enabling ATO Pump"); waitForTime(3);

    //Enable ATO pump
    ReefAngel.Relay.RelayMaskOff = B11111111;
    ReefAngel.Relay.Write();

    //display Water Change Complete
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "                      ");
    ReefAngel.LCD.DrawText(ModeScreenColor, DefaultBGColor, 2, 30, "Water Change Complete"); waitForTime(3);
    ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}

bool isSWBruteEmpty()
{
  // check status of IO Mod Port 2
  if ( ! ReefAngel.IO.GetChannel(2) )
      return true;
  return false;
}

void waitForTime(int seconds)
{
    bool done = false;
    tm.SetInterval(seconds);
    tm.Start();
    int t = tm.Trigger - now();
    do
    {
      // wait for specified seconds
      if ( (t >= 0) && ! tm.IsTriggered() )
        {
          // TODO finish countdown on screen
          // show countdown on screen
          //LCD.Clear(DefaultBGColor,60+(intlength(t)*5),100,100,108);
          //LCD.DrawText(DefaultFGColor,DefaultBGColor,60,100,t);
          wdt_reset();
          delay(200);
        }
        else
        {
          done = true;
        }
    } while ( !done );
    return;
}

void waitForIOChannel(byte channel)
{
    // TODO complete this function
    do
    {
      wdt_reset();
      // display something on screen
      delay(200);
      // TODO check the IO channel logic
    } while ( ReefAngel.IO.GetChannel(channel) );
}

//*****End WC Additions


void DrawCustomMain()
{
    int x,y;
    char text[10];
    // Dimming Expansion
    x = 15;
    y = 2;
    for ( int a=0;a<6;a++ )
    {
      if ( a>2 ) x = 75;
      if ( a==3 ) y = 2;
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Ch :" );
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+12,y,a );
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+24,y,ReefAngel.PWM.GetChannelValue(a) );
      y += 10;
    }
    pingSerial();

    // I/O Expansion
    byte bkcolor;
    x = 14;
    y = 34;
    for ( int a=0;a<6;a++ )
    {
      ReefAngel.LCD.DrawCircleOutline( x+(a*20),y,4,COLOR_MEDIUMORCHID );
      if ( ReefAngel.IO.GetChannel(a) ) bkcolor=COLOR_WHITE; else bkcolor=COLOR_GRAY;
      ReefAngel.LCD.FillCircle( x+(a*20),y,2,bkcolor );
    }
    pingSerial();

    // Parameters
#if defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 44, ReefAngel.Params,
    ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue() );
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 44, ReefAngel.Params );
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
    pingSerial();

    // Salinity
    ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,15,76, "SAL:" );
    ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,39,76, ReefAngel.Params.Salinity );
    pingSerial();

    // Main Relay Box
    byte TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox( 12, 90, TempRelay );
    pingSerial();

    // Relay Expansion
    TempRelay = ReefAngel.Relay.RelayDataE[0];
    TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
    TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
    ReefAngel.LCD.DrawOutletBox( 12, 104, TempRelay );
    pingSerial();

    // Date and Time
    ReefAngel.LCD.DrawDate( 6, 122 );
    pingSerial();
}

void DrawCustomGraph()
{
}

180G FOWLR
20GH QT#1
29G QT#2

Image
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

00Warpig00 wrote: fooled around with this toady and using the internal memory for me does not work.

my "InternalMemory.read(10)" ALWAYS = 255. Never goes to any other value that I can tell.
This is interesting. We may want to take a look at that to see if something is going wrong. Hard to say though, it could be a couple of things.
I've got the water change code working well and fully tested. I added a bunch of screen draws along the road so the controller tells me what is going on at any moment during the water change. I did notice that my controller stops responding to my wifi mod and any refreshes over the android app to see what is going on during the process with the relay ports IO ports etc. All queries to the controller during water change are met with a XML Parser error. When the mode is finished I need to press the joystick button to return to the main menu and they wifi can communicate again. not a huge problem since I am planning fully attended waterchanges for the indefinite future but it would be cool to still have the wifi mod working during the water change.
Yes, with the current setup, your controller will not respond to any wifi events at all. It is off in it's own little world doing what it needs to do. We can fix that though, it's not a big deal at all. It's actually quite simple to do.

As for the returning to normal operation automatically after it finishes, that should be pretty simple as well.
I also would like to change my buzzer function to have the buzzer beep/chirp for a quarter of a second every two minutes or so instead of just wailing about constantly. any ideas on how to do this would be welcomed.
This will just require the creation of another timer and a slight delay. There will be some timing issues to worry about but nothing major. It may not be "perfect" but we should be able to get it close to what you want. This will just take some more thought to accomplish.

Let me see what I can come up with for you regarding the other issues first and then we can tackle the buzzer last (unless you figure it out first). :)
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

Like I said, simple enough for the wifi processing. I added the pingSerial(); function call to the waitForTime and waitForIOChannel() function calls. Those calls are where the delays occur and where the function spends the most time. Inside those, while you are "waiting", you are also checking the wifi channel and processing any requests coming in.

A word of caution though. If you toggle any ports in this mode, you can interrupt or alter some or part of the water change process. So I would suggest only getting the status and not changing anything else with it.

Code: Select all

void waitForTime(int seconds)
{
    bool done = false;
    tm.SetInterval(seconds);
    tm.Start();
    int t = tm.Trigger - now();
    do
    {
      // check the wifi interface
      pingSerial();

      // wait for specified seconds
      if ( (t >= 0) && ! tm.IsTriggered() )
        {
          // TODO finish countdown on screen
          // show countdown on screen
          //LCD.Clear(DefaultBGColor,60+(intlength(t)*5),100,100,108);
          //LCD.DrawText(DefaultFGColor,DefaultBGColor,60,100,t);
          wdt_reset();
          delay(200);
        }
        else
        {
          done = true;
        }
    } while ( !done );
    return;
}

void waitForIOChannel(byte channel)
{
    // TODO complete this function
    do
    {
      wdt_reset();
      // display something on screen
      // check the wifi interface
      pingSerial();
      delay(200);
      // TODO check the IO channel logic
    } while ( ReefAngel.IO.GetChannel(channel) );
}
I still have to look at returning from the mode without having to press the button.
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Another Water change thread this one based on IO Mod flo

Post by binder »

Ok, another post with another answer for you....

Check out the function call "ReefAngelClass::ExitMenu()".
The last line in your function is this:

Code: Select all

    ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
You should remove that line and use this instead (from ReefAngelClass::ExitMenu()) :

Code: Select all

	// Handles the cleanup to return to the main screen
	ReefAngel.ClearScreen(DefaultBGColor);
	ReefAngel.DisplayedMenu = DEFAULT_MENU;
	DrawCustomGraph();
That should fix your problem with having to press the joystick and also with getting the screen to update properly.

That's all I've got for now. :ugeek:
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

binder wrote:
00Warpig00 wrote: fooled around with this toady and using the internal memory for me does not work.

my "InternalMemory.read(10)" ALWAYS = 255. Never goes to any other value that I can tell.
This is interesting. We may want to take a look at that to see if something is going wrong. Hard to say though, it could be a couple of things.

Not sure whats up with this either. I put a text draw of that variable in the middle of the main screen in the main loop. It was 255.

cleared the screen into WC mode and drew that variable in the middle of the screen during water change. still 255

Yes, with the current setup, your controller will not respond to any wifi events at all. It is off in it's own little world doing what it needs to do. We can fix that though, it's not a big deal at all. It's actually quite simple to do.

As for the returning to normal operation automatically after it finishes, that should be pretty simple as well.

I figured this was the cause I just didnt realize the pingSerial command was what it is... lol looks like an easy fix. Just would like to be able to see the status of things if needed and in case of an emergency be able to mask pumps off during WC.

This will just require the creation of another timer and a slight delay. There will be some timing issues to worry about but nothing major. It may not be "perfect" but we should be able to get it close to what you want. This will just take some more thought to accomplish.

Let me see what I can come up with for you regarding the other issues first and then we can tackle the buzzer last (unless you figure it out first). :)
I figured the beep was going to be a matter of turning the buzzer on then off quickly... the easy part the harder part is letting the controller continue to function while counting up to the delay time between beeps.

... wow I really messed up quoting that post. Oh well it still makes sense so I'll leave it alone. lol

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

binder wrote:Ok, another post with another answer for you....

Check out the function call "ReefAngelClass::ExitMenu()".
The last line in your function is this:

Code: Select all

    ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
You should remove that line and use this instead (from ReefAngelClass::ExitMenu()) :

Code: Select all

	// Handles the cleanup to return to the main screen
	ReefAngel.ClearScreen(DefaultBGColor);
	ReefAngel.DisplayedMenu = DEFAULT_MENU;
	DrawCustomGraph();
That should fix your problem with having to press the joystick and also with getting the screen to update properly.

That's all I've got for now. :ugeek:
I saw and had the EXIT MENU in my program for a while. last night when I was playing with it it was exiting properly... not sure where it went I must have lost it when cutting/pasting code and didnt remember what it was so put in that other menu call.

I will mess around some more with it tomorrow after work. Just finished hooking the controller back up to the tank and cleaning the tank and skimmer and some other fishie chores. wanted to see what was happening here... now it off to watch a movie.

Thanks again for the help. I pick things up pretty quickly. I am 80% hardware guy but I have some experience with VB scripting as my server login scripts at work are all VBS scripts. I just have no clue on the correct structuring and syntax of c++ I'm a complete hack in the coding world.

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Another Water change thread this one based on IO Mod flo

Post by rimai »

Are you sure 1/2s every 120 seconds?
Try this:

Code: Select all

ReefAngel.PWM.SetActinic(millis()%120000<500?buzzer:0);
ReefAngel.PWM.SetDaylight(millis()%120000<500?buzzer:0);
Roberto.
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

rimai wrote:Are you sure 1/2s every 120 seconds?
Try this:

Code: Select all

ReefAngel.PWM.SetActinic(millis()%120000<500?buzzer:0);
ReefAngel.PWM.SetDaylight(millis()%120000<500?buzzer:0);
No I'm not sure... lol I'm sure it yelping for a half a second will be annoying too... truth be told will probably end up more like 100ms on 120000ms off. Now I see where you are going with the code timing that seems pretty simple to modify. I guess the big thing is that I would like this behavior as a reminder to check the tank every couple of minutes until it is cleared and a variable (buzzer???) is set from something other than 0 back to 0. An alerter so to speak. An attention getter. beep.... beep.... "hey while you were gone your RO topoff Brute went empty and needs a refill", or "hey you can go turn the RO supply line off now or your gonna have a mess on your hands" kinda thing. Perfect world would be to have a "non critical" beep beep beep, and a "critical" BEEEEEEEEEEEEEEEEEEEP behavior if you get where I'm going with this.

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Another Water change thread this one based on IO Mod flo

Post by rimai »

Yeah, you can make any type of sound you wish.
Just need to know when and which sound to fire off :)
Roberto.
00Warpig00
Posts: 289
Joined: Wed May 16, 2012 9:52 pm

Re: Another Water change thread this one based on IO Mod flo

Post by 00Warpig00 »

rimai wrote:Are you sure 1/2s every 120 seconds?
Try this:

Code: Select all

ReefAngel.PWM.SetActinic(millis()%120000<500?buzzer:0);
ReefAngel.PWM.SetDaylight(millis()%120000<500?buzzer:0);
This generally seems to work but there is some time oddities.

I set it to

ReefAngel.PWM.SetActinic(millis()%30000<100?buzzer:0);
ReefAngel.PWM.SetDaylight(millis()%30000<100?buzzer:0);

or 100ms every 30 seconds and the beeps occur as follows. (I am very happy with the 100ms duration)

1st beep @30 seconds (+30)
2nd beep @1 minute (last+30)
3rd beep @ 2 minutes (last+60)
4th beep @ 3 minutes (last+60)
5th beep @4 minutes 30 seconds (last +90)
then sometimes one every 30 seconds one every minute or one every minute and a half or so.

Not sure what is going on. They all happen exactly on the same 30 second mark against the clock so there is no time drift just seeming to have multiples of 30 seconds. Not sure what the reason is.

ALL of the rest of the Code supplied is working great. clear screen and return to main menu after completed change is perfect and wifi updates are now working and all ports show the correct info during all modes of the waterchange from the android app. Now i just need to remedy my float switch issues with float switches erroneously reading active when they should not be. A few of the float switches were too close to pump magnets and I resolved those but i have put in two different "sump empty" float switches in the bottom of my sump that should only be active when the sump is empty and they both exhibit the same behavior. Inactive for about 30 seconds after I bump them but then they go active again. the strangeness is they are supposed to be active when the sump is empty which as far as I can gather means that the float ring is not staying afloat while fully submerged. grrr... If I can resolve that empty sump float switch problem I could actually do a REAL waterchange to put my new code to good use. Then a nice simple weekly ~30 gallon waterchange will become easy and routine instead of a PITA! lol

Nick
180G FOWLR
20GH QT#1
29G QT#2

Image
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Another Water change thread this one based on IO Mod flo

Post by rimai »

Try changing it to 100 instead of 40.
The buzzer is really not made to go that low on voltage.
Roberto.
Post Reply