Dual Tank, single controller

Do you have a question on how to do something.
Ask in here.
Post Reply
imfortney
Posts: 15
Joined: Sat Jun 14, 2014 8:30 pm
Location: Key Largo, FL

Dual Tank, single controller

Post by imfortney »

Well guys i want to control ATO, Fan (chiller), and Overheat functions for 2 different tanks.

I am hoping that you guys can help me with this.

Here is what I want to try:

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 <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>

////// Place global variable code below here
#define NUMBERS_8x16
void DrawCustomMain()
{
// the graph is drawn/updated when we exit the main menu &
// when the parameters are saved
ReefAngel.LCD.DrawDate(6, 112);
ReefAngel.LCD.DrawText(COLOR_ORANGERED, COLOR_DEEPSKYBLUE,14,8, "Fortney Money Pit");
pingSerial();

DrawStatus (20,80);
DrawParams (5,40);
DrawParamsa (0,10);
pingSerial();
byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 93, TempRelay);
}

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


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    ReefAngel.AddStandardMenu();  // Add Standard Menu
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port2Bit | Port6Bit | Port8Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port6Bit | Port8Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port3Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port2Bit | Port7Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 800 );

    // Feeeding and Water Change mode speed
    ReefAngel.DCPump.FeedingSpeed=0;
    ReefAngel.DCPump.WaterChangeSpeed=0;


    // Ports that are always on
    ReefAngel.Relay.On( Port1 );
          
    ////// Place additional initialization code below here
    //ReefAngel.CustomLabels[0]="ReturnPump";  
    //ReefAngel.CustomLabels[1]="Skimmer";  
    //ReefAngel.CustomLabels[2]="Kessil";  
    //ReefAngel.CustomLabels[3]="Nick  Fan";  
    //ReefAngel.CustomLabels[4]="Steph Fan";  
    //ReefAngel.CustomLabels[5]="Steph ATO";  
    //ReefAngel.CustomLabels[6]="Refugium";  
    //ReefAngel.CustomLabels[7]="Nick  ATO";  

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

void loop()
{
    ReefAngel.Relay.DelayedOn( Port2,20 );
    ReefAngel.MHLights( Port3,11,00,21,00,0 );
    ReefAngel.StandardFan( Port5,776,781 );
    ReefAngel.Relay.Set( Port7, !ReefAngel.Relay.Status( Port3 ) );
    ReefAngel.SingleATO( true,Port6,10,0 );    
    ReefAngel.SingleATO( false,Port8,10,0 );
    if (ReefAngel.Params.Temp[T2_PROBE]>800) ReefAngel.Relay.Off(Port4);
    if (ReefAngel.Params.Temp[T2_PROBE]<790) ReefAngel.Relay.On(Port4);
    
    ////// Place your custom code below here
    if (hour()>=8 && hour()<20)
{
    ReefAngel.PWM.SetDaylight( ElseMode(70,30,true) ); // Else Mode at 70% +/- 30% on sync mode
}
else if (hour()>=20 && hour()<23)
{
    ReefAngel.PWM.SetDaylight( NutrientTransportMode(40,80,200,true) ); // Nutrient Transport 40%minspeed - 80%maxspeed - 200ms 
}    
    else if (hour()>=23 || hour()<8)
{
    ReefAngel.PWM.SetDaylight( ElseMode(45,15,true) ); // Else Mode at 45% +/- 15% on sync mode
}
if (hour()>=11 && hour()<22)
{
    ReefAngel.PWM.SetActinic( ElseMode(70,30,false) ); // Else Mode at 70% +/- 30% on anti-sync mode
}
else if (hour()>=22 || hour()<1)
{
    ReefAngel.PWM.SetActinic( NutrientTransportMode(40,80,200,false) ); // Nutrient Transport 40%minspeed - 80%maxspeed - 200ms 
}    
    else if (hour()>=1 && hour()<11)
{
    ReefAngel.PWM.SetActinic( ElseMode(45,15,false) ); // Else Mode at 45% +/- 15% on anti-sync mode
}
    ////// Place your custom code above here

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

void DrawParamsa(int x, int y){
char buf[16];
  ReefAngel.LCD.DrawText(DPColor,DefaultBGColor,x+40,y+10,"Steph:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+78, y+10,1);
ReefAngel.LCD.DrawText(APColor,DefaultBGColor,x+40,y+20,"Nick:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetActinicValue(),APColor, x+78, y+20,1);

}

void DrawParams(int x, int y) {
  char buf[16];

  ReefAngel.LCD.DrawText(COLOR_INDIGO,DefaultBGColor,x+5,y,"Temp:");
  ReefAngel.LCD.DrawText(COLOR_INDIGO,DefaultBGColor,x+80, y, "PH:");
  // Temp and PH
  y+=10;

  ConvertNumToString(buf, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T1TempColor, DefaultBGColor, x+5, y, buf, Num8x16);
  ConvertNumToString(buf, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+80, y, buf, Num8x16);
  y+=5;

}

void DrawStatus(int x, int y) {
  int t=x;
  
  ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,15,y,"High",Font8x16);
  ReefAngel.LCD.DrawLargeText(COLOR_ORANGERED,DefaultBGColor,85,y,"Low",Font8x16);
  
  if (ReefAngel.HighATO.IsActive()) {
    ReefAngel.LCD.FillCircle(55,y+3,5,COLOR_INDIGO);
  } else {
    ReefAngel.LCD.FillCircle(55,y+3,5,COLOR_ORANGERED);
  }
  
  if (ReefAngel.LowATO.IsActive()) {
    ReefAngel.LCD.FillCircle(70,y+3,5,COLOR_ORANGERED);
  } else {
    ReefAngel.LCD.FillCircle(70,y+3,5,COLOR_INDIGO);
  }
}

void DrawCustomGraph()
{
}

byte ElseMode( byte MidPoint, byte Offset, boolean WaveSync )
{
  // Static's only initialize the first time they are called
  static unsigned long LastChange=millis();        // Set the inital time that the last change occurred
  static int Delay = random( 500, 3000);           // Set the initial delay
  static int NewSpeed = MidPoint;                  // Set the initial speed
  static int AntiSpeed = MidPoint;                 // Set the initial anti sync speed
  if ((millis()-LastChange) > Delay)               // Check if the delay has elapsed
  {
    Delay=random(500,5000);                        // If so, come up with a new delay
    int ChangeUp = random(Offset);                 // Amount to go up or down
    if (random(100)<50)                            // 50/50 chance of speed going up or going down
    {
      NewSpeed = MidPoint - ChangeUp;
      AntiSpeed = MidPoint + ChangeUp;
    }
    else
    {
      NewSpeed = MidPoint + ChangeUp;
      AntiSpeed = MidPoint - ChangeUp;
    }
    LastChange=millis();                           // Reset the time of the last change
  }
  if (WaveSync)
  {
    return NewSpeed;
  }
  else
  {
    return AntiSpeed;
  }
}
I know i missed something somewhere.

Thanks for the help guys
imfortney
Posts: 15
Joined: Sat Jun 14, 2014 8:30 pm
Location: Key Largo, FL

Re: Dual Tank, single controller

Post by imfortney »

well i am running two fans on two temp probes and i am also running two separate single ATO. the only thing i am missing is two separate overheat functions.

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 <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>

////// Place global variable code below here
#define NUMBERS_8x16
void DrawCustomMain()
{
// the graph is drawn/updated when we exit the main menu &
// when the parameters are saved
ReefAngel.LCD.DrawDate(6, 112);
ReefAngel.LCD.DrawText(COLOR_ORANGERED, COLOR_DEEPSKYBLUE,14,8, "Our Little Oceans");
pingSerial();

DrawStatus (20,80);
DrawParams (5,40);
DrawParamsa (0,10);
pingSerial();
byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 93, TempRelay);
}

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


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    ReefAngel.AddStandardMenu();  // Add Standard Menu
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port2Bit | Port6Bit | Port8Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port6Bit | Port8Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port3Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port2Bit | Port7Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 840 );

    // Feeeding and Water Change mode speed
    ReefAngel.DCPump.FeedingSpeed=0;
    ReefAngel.DCPump.WaterChangeSpeed=0;


    // Ports that are always on
    ReefAngel.Relay.On( Port1 );
          
    ////// Place additional initialization code below here
    //ReefAngel.CustomLabels[0]="ReturnPump";  
    //ReefAngel.CustomLabels[1]="Skimmer";  
    //ReefAngel.CustomLabels[2]="Kessil";  
    //ReefAngel.CustomLabels[3]="Nick  ATO";  
    //ReefAngel.CustomLabels[4]="Steph Fan";  
    //ReefAngel.CustomLabels[5]="Steph ATO";  
    //ReefAngel.CustomLabels[6]="Refugium";  
    //ReefAngel.CustomLabels[7]="Nick  Fan";  

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

void loop()
{
    ReefAngel.Relay.DelayedOn( Port2,20 );
    ReefAngel.MHLights( Port3,11,00,21,00,0 );
    ReefAngel.StandardFan( Port5,776,781 );
    ReefAngel.Relay.Set( Port7, !ReefAngel.Relay.Status( Port3 ) );
    ReefAngel.SingleATO( true,Port6,10,0 );    
    ReefAngel.SingleATO( false,Port4,10,0 );
    if (ReefAngel.Params.Temp[T2_PROBE]>776) ReefAngel.Relay.On(Port8);
    if (ReefAngel.Params.Temp[T2_PROBE]<781) ReefAngel.Relay.Off(Port8);
    
    ////// Place your custom code below here
    if (hour()>=8 && hour()<20)
{
    ReefAngel.PWM.SetDaylight( ElseMode(70,30,true) ); // Else Mode at 70% +/- 30% on sync mode
}
else if (hour()>=20 && hour()<23)
{
    ReefAngel.PWM.SetDaylight( NutrientTransportMode(40,80,200,true) ); // Nutrient Transport 40%minspeed - 80%maxspeed - 200ms 
}    
    else if (hour()>=23 || hour()<8)
{
    ReefAngel.PWM.SetDaylight( ElseMode(45,15,true) ); // Else Mode at 45% +/- 15% on sync mode
}
if (hour()>=11 && hour()<22)
{
    ReefAngel.PWM.SetActinic( ElseMode(70,30,false) ); // Else Mode at 70% +/- 30% on anti-sync mode
}
else if (hour()>=22 || hour()<1)
{
    ReefAngel.PWM.SetActinic( NutrientTransportMode(40,80,200,false) ); // Nutrient Transport 40%minspeed - 80%maxspeed - 200ms 
}    
    else if (hour()>=1 && hour()<11)
{
    ReefAngel.PWM.SetActinic( ElseMode(45,15,false) ); // Else Mode at 45% +/- 15% on anti-sync mode
}
    ////// Place your custom code above here

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

void DrawParamsa(int x, int y){
char buf[16];
  ReefAngel.LCD.DrawText(DPColor,DefaultBGColor,x+40,y+10,"Steph:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+78, y+10,1);
ReefAngel.LCD.DrawText(APColor,DefaultBGColor,x+40,y+20,"Nick:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetActinicValue(),APColor, x+78, y+20,1);

}

void DrawParams(int x, int y) {
  char buf[16];

  ReefAngel.LCD.DrawText(COLOR_INDIGO,DefaultBGColor,x+5,y,"Steph:");
  ReefAngel.LCD.DrawText(COLOR_INDIGO,DefaultBGColor,x+80, y, "Nick:");
  // Temp and PH
  y+=10;

  ConvertNumToString(buf, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T1TempColor, DefaultBGColor, x+5, y, buf, Num8x16);
  ConvertNumToString(buf, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T2TempColor, DefaultBGColor, x+80, y, buf, Num8x16);
  y+=5;

}

void DrawStatus(int x, int y) {
  int t=x;
  
  ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,15,y,"Nick",Font8x16);
  ReefAngel.LCD.DrawLargeText(COLOR_ORANGERED,DefaultBGColor,85,y,"Steph",Font8x16);
  
  if (ReefAngel.HighATO.IsActive()) {
    ReefAngel.LCD.FillCircle(55,y+3,5,COLOR_ORANGERED);
  } else {
    ReefAngel.LCD.FillCircle(55,y+3,5,COLOR_INDIGO);
  }
  
  if (ReefAngel.LowATO.IsActive()) {
    ReefAngel.LCD.FillCircle(70,y+3,5,COLOR_ORANGERED);
  } else {
    ReefAngel.LCD.FillCircle(70,y+3,5,COLOR_INDIGO);
  }
}

void DrawCustomGraph()
{
}

byte ElseMode( byte MidPoint, byte Offset, boolean WaveSync )
{
  // Static's only initialize the first time they are called
  static unsigned long LastChange=millis();        // Set the inital time that the last change occurred
  static int Delay = random( 500, 3000);           // Set the initial delay
  static int NewSpeed = MidPoint;                  // Set the initial speed
  static int AntiSpeed = MidPoint;                 // Set the initial anti sync speed
  if ((millis()-LastChange) > Delay)               // Check if the delay has elapsed
  {
    Delay=random(500,5000);                        // If so, come up with a new delay
    int ChangeUp = random(Offset);                 // Amount to go up or down
    if (random(100)<50)                            // 50/50 chance of speed going up or going down
    {
      NewSpeed = MidPoint - ChangeUp;
      AntiSpeed = MidPoint + ChangeUp;
    }
    else
    {
      NewSpeed = MidPoint + ChangeUp;
      AntiSpeed = MidPoint - ChangeUp;
    }
    LastChange=millis();                           // Reset the time of the last change
  }
  if (WaveSync)
  {
    return NewSpeed;
  }
  else
  {
    return AntiSpeed;
  }
}
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Dual Tank, single controller

Post by binder »

if you are missing the overheat functions, you will want to look at the libraries and specifically reefangel/reefangel.cpp file to see how the overheat checks are performed. then you will want to replicate that for your second temp probe.
i cant give you any examples currently as im on my ipad but i should be able to later tonight if someone else hasnt chimed in.


Sent from my iPad mini
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Dual Tank, single controller

Post by binder »

Ok. I created the second overheat check function for you. It allows you to independently control what ports get shutoff when the second overheat check happens. So you can control both separately. The only downside is that the overheat clearing will have to be coded in differently because the function is a custom function. Anyways, here's the start of it:
place these lines above the setup and init functions (above the ///Place global variable code above here)

Code: Select all

time_t Overheatmillis2;
byte OverheatShutoffPorts2;
then, inside the setup() function, you can initialize the shutoffports:

Code: Select all

void setup() {
// ... other code
    // set this just like the ReefAngel.OverheatShutoffPorts is set
    OverheatShutoffPorts2 = 0;
}
Now copy and paste these functions somewhere in the INO file, probably towards the bottom. It's set to operate on the 2nd temp probe. This can be changed though. It's also set to use the same overheat temp as the regular overheat check function. if you need an additional overheat temperature, we can easily add that in for you too.

Code: Select all

void OverheatCheck2()
{
	// if overheat probe exceeds the temp
       // use T1_PROBE, T2_PROBE or T3_PROBE
	if ( ReefAngel.Params.Temp[T2_PROBE] <= InternalMemory.OverheatTemp_read() )
		Overheatmillis2=millis();
	if (millis()-Overheatmillis2>3000) // Only flag overheat if we have overheat for 3 seconds
	{
		LED.On();
		bitSet(ReefAngel.AlertFlags,OverheatFlag);
#ifdef ENABLE_EXCEED_FLAGS
		InternalMemory.write(Overheat_Exceed_Flag, 1);
#endif  // ENABLE_EXCEED_FLAGS
		// invert the ports that are activated
		ReefAngel.Relay.RelayMaskOff &= ~OverheatShutoffPorts2;
	}
}

void OverheatClear2()
{
	LED.Off();
	bitClear(ReefAngel.AlertFlags,OverheatFlag);
#ifdef ENABLE_EXCEED_FLAGS
	InternalMemory.write(Overheat_Exceed_Flag, 0);
#endif  // ENABLE_EXCEED_FLAGS
	ReefAngel.Relay.RelayMaskOff |= OverheatShutoffPorts2;
	ReefAngel.Relay.Write();
}
the last thing you will need to do is inside the loop() function, you will need to call the overheatcheck function towards the bottom, above your portal line

Code: Select all

void loop() {
// ...other code

    OverheatCheck2();
    // Portal()
    // ShowInterface()
}
Let me know if you have trouble placing this in your INO file and I can place it for you. I opted not for simplicity and to explain each code block a little bit.

Like I was saying earlier, you cannot easily clear the overheat check and restore the flagged off ports because you cannot call OverheatClear2(). You would have to either: a) add a menu item to call that function or b) setup a memory location that if it is set to 1, it calls the function and then resets itself back to 0 to clear the overheat.
i can help with the second option (b), later if that's what you want (which it probably will be). Otherwise, we will have to modify the libraries to make things work properly for you...it can be done but would mean you would have to re-add your changes every time you upgraded the libraries...so it's not really recommended. option B is probably your best choice.

I should be able to help with that tomorrow when I have some time to sit down and write it out.
imfortney
Posts: 15
Joined: Sat Jun 14, 2014 8:30 pm
Location: Key Largo, FL

Re: Dual Tank, single controller

Post by imfortney »

Wow! Thank you very much! I will play with that tomorrow.

I have had to make some changes to my INO due to not following instructions causing my 2nd fan to rapidly toggle. I fixed it by copy and paste from another thread, I believe from Roberto. Now if only this stupid goni would open up I'd be really happy


Sent from my iPhone using Tapatalk
Post Reply