Page 1 of 1

Alex's 75 gallon mostly automated tank

Posted: Mon Sep 17, 2012 8:02 pm
by alexwbush
So I've been with you guys for a while and never posted my builds. I will document here and share code that might be helpful to all of you!

I will place my custom code as I develop it to hopefully help others in their automation and customization efforts.

Webcam Feed:
Image

Setup/Equipment:
RA+ w/ expansions: 2nd relay, salinity, RF, dosers
Tank: Leemar Glass 75 gallon 36"x24"x20"
Sump: 20 gallon long
Refugium: Large Aquafuge
Lighting: 2x Ecotech Radions
Protein Skimmer: ASM G3
Circulation: MP 40
Return: Eheim 1262
Other equipment: BRS Dual Chamber (Carbon & GFO) Reactor, BRS Bio Pellets, RA Dosing

Banners:
New setup tank:
Image

Other stats:
WL: http://forum.reefangel.com/status/chart ... &filter=WL

Coding Plan:
Custom screen in progress
Image

Code: Select all

void DrawCustomMain()
{
  byte x = 6;
  byte y = 2;
  byte t;
  char text[7];

  /* Drawing this:
   
   01/01/12 00:00:00 AM
   ----------------------
   Disp 79.9  pH     8.00
   Sump 79.9  Sal    0.60
   Room 77.7  WtrLvl Ok
   
   1 2 3 4 5 6 7 8
   1 2 3 4 5 6 7 8
   
   Moon Waning Crescent
   Intensity 88%
   Sunrise   06:15
   Sunset    18:12
  */
   
  /* Colors used in this script:
     DefaultFGColor   - For basic font and line
     DefaultBGColor   - For background color
     PHColor          - For values that may change
     OutletOnBGColor  - For okay water level
     OutletOffBGColor - For low water level
     
     To change colors, modify these values in ReefAngel_CustomColors.h file
  */

  ReefAngel.LCD.DrawDate(6, 2);
  ReefAngel.LCD.Clear(DefaultFGColor, 1, 11, 128, 11);
  pingSerial();

  //ReefAngel.LCD.DrawText(fcolor,bcolor,x,y,"text");

  //Line 1 - Display Temp & pH
  x = 8;
  y = 15;
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Disp");
  x += 30;
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T1_PROBE], PHColor, x, y, 10);
  x = 70; 
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"pH");
  x += 30;
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.PH, PHColor, x, y, 100);

  //Line 2 - Sump & Salinity
  x = 8;
  y += 10; 
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Sump");
  x += 30;
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], PHColor, x, y, 10);
  x = 70; 
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Sal");
  x += 30;
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Salinity, PHColor, x, y, 10);

  //Line 3 - Room
  x = 8;
  y += 10; 
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Room");
  x += 30;
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T3_PROBE], PHColor, x, y, 10);
  x = 70;
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Lvl");
  x += 30;
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.WaterLevel.GetLevel(), PHColor, x, y, 1);

  //Lines 4 and 5 - Relays
  x = 12; 
  y += 15;
  // draw main relay
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(x, y, TempRelay);

  //Line 3 - Room
  x = 8;
  y += 20; 
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Lvl");
  x += 30;
  ReefAngel.LCD.DrawSingleMonitor(InternalMemory.read(258), PHColor, x, y, 1);
  x = 70;
  ReefAngel.LCD.DrawSingleMonitor(InternalMemory.read(259), PHColor, x, y, 1);
  x += 30;
  ReefAngel.LCD.DrawSingleMonitor(topofflevel, PHColor, x, y, 1);

  pingSerial();
}
Radion w/moon cycle and variable day periods in progress
First, paste these variables in the area marked "Place global variable code below/above here"

Code: Select all

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

byte starthr = 8; //start hour for radion cycle (0-23)
byte startmin = 0; //start minute for radion cycle (0-59)
byte endhr = 22; //end hour for radion cycle (0-23)
byte endmin = 0; //end min for radion cycle (0-59)
byte intensity = 80; //intensity of radion cycle (0-100)

////// Place global variable code above here
Then paste the following in main code:

Code: Select all

  /* Radion custom curve
    For testing:
    ReefAngel.RF.SetChannel( Radion_White, PWMParabola(10,0,21,0,0,75,0) );
    ReefAngel.RF.SetChannel( Radion_RoyalBlue, PWMParabola(8,0,22,0,0,100,0) );
    ReefAngel.RF.SetChannel( Radion_Red, PWMParabola(11,30,21,0,0,20,0) );
    ReefAngel.RF.SetChannel( Radion_Green, PWMParabola(12,0,19,0,0,30,0) );
    ReefAngel.RF.SetChannel( Radion_Blue, PWMParabola(9,0,21,0,0,45,0) );
    ReefAngel.RF.SetChannel( Radion_Intensity, PWMParabola(8,0,22,0,0,100,0) );
    
    ReefAngel.RF.SetChannel( Radion_RoyalBlue, MoonPhase() );
  */

  ReefAngel.RF.UseMemory = false;
    ReefAngel.RF.SetChannel( Radion_White, PWMParabola(starthr+2,startmin,endhr-1,endmin,0,intensity*.75,0) );
    ReefAngel.RF.SetChannel( Radion_Red, PWMParabola(starthr+3,startmin+30,endhr-1,endmin,0,intensity*.2,0) );
    ReefAngel.RF.SetChannel( Radion_Green, PWMParabola(starthr+4,startmin,endhr-3,endmin,0,intensity*.3,0) );
    ReefAngel.RF.SetChannel( Radion_Intensity, PWMParabola(starthr,startmin,endhr,endhr,0,intensity,0) );
    
    /* Radion moon cycle
      Currently controls RoyalBlue.  If normal daylight, run defined parabola based on start and end radion cycle parameters (aka day cycle).  If after hours, run moonlight.
    */
    if ( (hour() < starthr && (minute() < startmin || startmin == 0) ) || (hour() > endhr && minute() > endmin) ) // If time time is before or after normal daylight cycle
      ReefAngel.RF.SetChannel( Radion_RoyalBlue, MoonPhase() ); // Run moonphase on RoyalBlue    
    else // Or else...
    {
      ReefAngel.RF.SetChannel( Radion_RoyalBlue, PWMParabola(starthr,startmin,endhr,endmin,0,intensity,0) ); // Run day cycle parabola
      ReefAngel.Relay.On(Port4); // And turn on the Vortech
    }
      
    if ( second()==0 ) ReefAngel.RF.RadionWrite();
Auto water change pending

Automated feeding complete

Code: Select all

  /* Auto feeding mode starts.  
   Feeder set for 17:30, start feeding mode at 17:25. */
  if ( hour() == 17 && minute() == 25 && second() ==0 ) //if time is 17:25:00
  {
    ReefAngel.FeedingModeStart(); //start feeding mode
  }

Re: Alex's 75 gallon mostly automated tank

Posted: Mon Sep 17, 2012 8:27 pm
by alexwbush
Second post will be my full current code.

Updated 3/2/15

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

#include <WiFiAlert.h>

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


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


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    ReefAngel.Use2014Screen();  // Let's use 2014 Screen 
    ReefAngel.AddSalinityExpansion();  // Salinity Expansion Module
    ReefAngel.AddWaterLevelExpansion();  // Water Level Expansion Module
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port8Bit;
    ReefAngel.FeedingModePortsE[0] = Port5Bit | Port6Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port7Bit | Port8Bit;
    ReefAngel.WaterChangePortsE[0] = Port3Bit | Port4Bit | Port5Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port2Bit;
    ReefAngel.LightsOnPortsE[0] = Port1Bit | Port2Bit | Port6Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port2Bit | Port3Bit | Port5Bit;
    ReefAngel.OverheatShutoffPortsE[0] = Port1Bit | Port2Bit | Port3Bit | Port5Bit | Port6Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;


    // Ports that are always on
    ReefAngel.Relay.On( Port1 );
    ReefAngel.Relay.On( Port5 );
    ReefAngel.Relay.On( Port8 );
    ReefAngel.Relay.On( Box1_Port1 );
    ReefAngel.Relay.On( Box1_Port2 );
    ReefAngel.Relay.DelayedOn( Box1_Port5 ); //turn on skimmer 10 min delay
    ReefAngel.Relay.On( Box2_Port1 ); //turn on Auto Feeding

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

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

void loop()
{
    ReefAngel.MoonLights( Port2 );        //Turns on 20:00, off at 09:30
    ReefAngel.StandardHeater( Port3 );
    ReefAngel.WaterLevelATO( Port4 );
    ReefAngel.DosingPumpRepeat1( Port6 );
    ReefAngel.DosingPumpRepeat2( Port7 );
    ReefAngel.Relay.DelayedOn( Box1_Port5 );
    ReefAngel.Relay.Set( Box1_Port6, !ReefAngel.Relay.Status( Port8 ) );
//    ReefAngel.PWM.SetDaylight( MoonPhase() );
//    ReefAngel.PWM.SetActinic( MoonPhase() );

    ////// Place your custom code below here
    
    RunRadion();       //Runs Radion
    DailyFeed();       //Automatic fish feeding
    NightMode();       //Runs Night mode
    AutoWaterChange();  //Runs Auto water change
    
    DailyReport();     //Sends Daily Reports

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

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

void NightMode(){
  // Turn on Night Mode if Fuge light is on (Fuge comes on at night)
    if (ReefAngel.Relay.Status( Port2 )== 1 && ReefAngel.RF.Mode!=Night) 
    {
      //ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Night,20,0);
    }
    else
    {
      ReefAngel.RF.SetMode(Night_Stop,0,0);
      //ReefAngel.RF.UseMemory=true;
    }
}

void DailyFeed(){
      /* Auto feeding mode starts.  
     Feeder set for 12:00, start feeding mode at 11:55. */
    if (ReefAngel.Relay.Status(Box2_Port1)==1)
    {
      if ( hour() == 11 && minute() == 55 && second() ==0 ) //if time is 11:55:00
      {
        ReefAngel.FeedingModeStart(); //start feeding mode
      } 
    }
}  

void DailyReport() { 
   static WiFiAlert dailyReport;
   char msg[32];    
   char temp[10];
   char ph[10];

   if ((now()+(9*SECS_PER_HOUR))%(12*SECS_PER_HOUR)==0) {
     dtostrf((float)ReefAngel.Params.Temp[T1_PROBE]/10,3, 1, temp);
     dtostrf((float)ReefAngel.Params.PH/100,4, 2, ph);
     sprintf(msg,"Daily Report: Temp:+%s+PH:+%s+WL:+%d",temp,ph,ReefAngel.WaterLevel.GetLevel());
     dailyReport.Send(msg);
     
   /*
   if ((now()+(9*SECS_PER_HOUR))%(12*SECS_PER_HOUR)==0) {
     dtostrf((float)ReefAngel.Params.Temp[T1_PROBE]/10,3, 1, temp);
     dtostrf((float)ReefAngel.Params.PH/100,4, 2, ph);
     sprintf(msg,"Temp:+%s+PH:+%s+WL:+%d",temp,ph,ReefAngel.WaterLevel.GetLevel());
     dailyReport.Send(msg);
     */
   }
}
void RunRadion()
{
  //ReefAngel.RF.SetChannel
  //ReefAngel.RF.UseMemory = true;
  if(ReefAngel.Relay.Status(Box2_Port6)==1 || ReefAngel.Relay.Status(Box2_Port7)==1 || ReefAngel.Relay.Status(Box2_Port8)==1)
    ConstantRadion();        //Runs radions on constant level (for overrides)
  else if( ReefAngel.Relay.Status(Port2)== 1 ) //Try this: hour() == 11 && minute() == 55 && second() ==0
    RadionNight();      //Runs Radion in night mode
  else{ 
    ReefAngel.RF.ChannelWhiteSlope();
    ReefAngel.RF.ChannelRoyalBlueSlope();
    ReefAngel.RF.ChannelRedSlope();
    ReefAngel.RF.ChannelGreenSlope();
    ReefAngel.RF.ChannelBlueSlope();
    ReefAngel.RF.ChannelIntensitySlope();
  }
  
}

void RadionNight() {
    ReefAngel.RF.SetChannel( Radion_White, 0 );
    ReefAngel.RF.SetChannel( Radion_RoyalBlue, 100 );
    ReefAngel.RF.SetChannel( Radion_Red, 0 );
    ReefAngel.RF.SetChannel( Radion_Green, 0 );
    ReefAngel.RF.SetChannel( Radion_Blue, 0 );
    ReefAngel.RF.SetChannel( Radion_Intensity, MoonPhase() );
}

void ConstantRadion() {
    byte white=InternalMemory.RadionSlopeEndW_read();
    byte royal_blue=InternalMemory.RadionSlopeEndRB_read();
    byte red=InternalMemory.RadionSlopeEndR_read();
    byte green=InternalMemory.RadionSlopeEndG_read();
    byte blue=InternalMemory.RadionSlopeEndB_read();
    byte intensity=InternalMemory.RadionSlopeEndI_read(); 
    static time_t t;
    int runtime=180;
    
    if(ReefAngel.Relay.Status(Box2_Port8)==1) //Movie mode
    {
      if(ReefAngel.Relay.isMaskOn(Box2_Port8))
        t=now();
      if(now()-t < runtime){
        intensity=0;
        ReefAngel.Relay.Override(Box1_Port6, 0); //refugium light off
      }
      else ReefAngel.Relay.Override(Box2_Port8,2);
    }
    else
    {
       ReefAngel.Relay.Override(Box1_Port6, 2); //refugium light auto
       if(ReefAngel.Relay.Status(Box2_Port7)==1) //Actinic
       {
          white=0;
          blue=0;
          royal_blue=0;
          green=0;
          red=0;
          intensity=75;
        }
        else 
        {
          white=InternalMemory.RadionSlopeEndW_read();
          royal_blue=InternalMemory.RadionSlopeEndRB_read();
          red=InternalMemory.RadionSlopeEndR_read();
          green=InternalMemory.RadionSlopeEndG_read();
          blue=InternalMemory.RadionSlopeEndB_read();
          intensity=InternalMemory.RadionSlopeEndI_read(); 
        }
    }
    ReefAngel.RF.SetChannel( Radion_White, white );
    ReefAngel.RF.SetChannel( Radion_RoyalBlue, royal_blue );
    ReefAngel.RF.SetChannel( Radion_Red, red );
    ReefAngel.RF.SetChannel( Radion_Green, green );
    ReefAngel.RF.SetChannel( Radion_Blue, blue );
    ReefAngel.RF.SetChannel( Radion_Intensity, intensity );
    
    /*
    10k:
          white=100;
          blue=75;
          royal_blue=75;
          green=100;
          red=100;
          intensity=75;
    14k:
          white=75;
          blue=100;
          royal_blue=100;
          green=75;
          red=75;
          intensity=75;
    20k:
          white=37;
          blue=100;
          royal_blue=100;
          green=17;
          red=37;
          intensity=75;
     */
}



void AutoWaterChange(){
    /* Automatic water change
    Trigger by Box2_Port3 (fake relay) that can be triggered by portal or RA app. Will turn on waste pump in sump is water
    level is above low sump level (memory location 340) or if waste bucket is full. Then will turn off waste pump and turn on
    fresh water pump to pump in water until sump water level is returned to normal. Meanwhile, return, skimmer, and heater
    should continue to operate normally.
    
    Utilized ports:
     Port 4       ATO: toggled off in auto water change
     Box1_Port5   Skimmer: will not exit mode unless skimmer is on (to account for lower water level when on)
     Box1_Port6   Sump light: toggled on in auto water change
     Box1_Port7   Waste water pump: Maxijet 1200 located in sump with drain hose to waste bucket
     Box1_Port8   Fresh water pump: 
     Box2_Port3   Auto Water Change trigger: fake relay box used for setting various "modes"
    
    Variables:
     WaterLevel.GetLevel(0)    Water level sensor in pump: Returns a value 0-100+
     HighATO.IsActive()        Float switch on waste bucket: Returns a value to indicate whether float switch is on bottom or floating
    
    Memory locations:
     Location 331   (ATO Level Low Value set @ 62)
     Location 332   (ATO Level High Value) (NOT UTILIZED, but could be helpful for changes)
     
     Location 340   (Water Level 1 Min Value -> Used for low water level in sump... set @ 25)
     */
    
    byte topofflevel=InternalMemory.read(332);
    byte sumplowlevel=InternalMemory.read(340);
    if (ReefAngel.Relay.Status(Box2_Port3)==1)
    {
      ReefAngel.Relay.Override(Box1_Port6, 1); //turn on sump light
      ReefAngel.Relay.Override(Port4, 0); //turn off ATO
      /* Drain waste water from sump if:
         1. Water level is above the low sump level (Location 340/"Water Level 1 Min Value")
         2. AND the ATO high level is not met (waste bucket NOT full)
         3. AND water fill is not on */
      if (ReefAngel.WaterLevel.GetLevel(0) > sumplowlevel && ReefAngel.HighATO.IsActive() && ReefAngel.Relay.Status(Box1_Port8)==0) 
      {
        ReefAngel.Relay.On(Box1_Port7); //turn on drain/waste pump
      }
      else ReefAngel.Relay.Off(Box1_Port7); //turn off drain/waste pump
      /* End waste water */
  
      /* Fill with fresh salt water if:
         1. Water level is below normal high level of autotop off (Location 332/"ATO Level High Value")
         2. AND waste pump is not on
         3. AND skimmer is on (to account for water level difference) */
      if (ReefAngel.WaterLevel.GetLevel(0) < topofflevel && ReefAngel.Relay.Status(Box1_Port7)==0 && ReefAngel.Relay.Status(Box1_Port5)==1)
      {
        ReefAngel.Relay.On(Box1_Port8); //turn on drain/waste pump
      }
      else ReefAngel.Relay.Off(Box1_Port8); //turn off fresh saltwater pump
      /* End clean water fill */
      
      /* Exit auto water change (make Box2_Port3 auto) if:
         1. Waste pump is off
         2. AND fresh water pump is off */
      if (ReefAngel.Relay.Status(Box1_Port7)==0 && ReefAngel.Relay.Status(Box1_Port8)==0)
      {
        ReefAngel.Relay.Override(Box2_Port3, 2); //auto water change back to auto
      }
    }
    
    else
    {
      ReefAngel.Relay.Override(Box1_Port6, 2); //auto sump light
      ReefAngel.Relay.Override(Port4, 2); //auto ATO  
    }
}

void HoldingCode(){
      

    
    /* Override for skimmer cleaning */
/*    static unsigned long SkimmerTimer;
    if (ReefAngel.Relay.Status(Box2_Port2)==1) SkimmerTimer=now();
    
    if(now()-SkimmerTimer>0 && now()-SkimmerTimer<600) //600s = 10min
    {
      ReefAngel.Relay.Override(Box1_Port5, 0); //turn off skimmer
      ReefAngel.Relay.Override(Box1_Port6, 1); //turn on sump light

    }  
    else 
    {
      ReefAngel.Relay.Override(Box2_Port2, 2);
      ReefAngel.Relay.Override(Box1_Port5, 2); //turn off skimmer
      ReefAngel.Relay.Override(Box1_Port6, 2); //turn on sump light
      
//      ReefAngel.Relay.Off(Box1_Port6); //turn off sump light
    }
    
    
      
    //180 - 3 min (for test)
    //1800 sec = 30 min
    //3600 sec = 60 min  
/*    if(now()-AutoWaterChange>0 && now()-AutoWaterChange<180 && ReefAngel.WaterLevel.GetLevel(0) >0 && ReefAngel.HighATO.IsActive())
    {
//      ReefAngel.Relay.Override(Port3,0); //turn off heater
//      ReefAngel.Relay.Override(Port4,0); //turn off ATO
//      ReefAngel.Relay.Override(Box1_Port5,0); //turn off skimmer
      ReefAngel.Relay.Override(Box1_Port6,1); //turn on sump light
      ReefAngel.Relay.Override(Box1_Port7,1); //turn on waste pump, pump water out
    }
    else
    {
      ReefAngel.Relay.Override(Box1_Port6,2); //turn on sump light
      ReefAngel.Relay.Override(Box1_Port7,2); //turn on waste pump, pump water out
    }


/*    else if (now()-AutoWaterChange>180 && ReefAngel.WaterLevel.GetLevel(0) < 100)
    {
      ReefAngel.Relay.Override(Box1_Port7,2); //turn off waste pump, pump water out
      ReefAngel.Relay.Override(Box1_Port8,1); //turn on fresh saltwater, pump water in
    }
    else 
    {
      ReefAngel.Relay.Override(Port3,2); //return heater to auto
      ReefAngel.Relay.Override(Port4,2); //return ATO to auto
      ReefAngel.Relay.Override(Box1_Port6,2);  //turn off sump light
      ReefAngel.Relay.Override(Box1_Port8,2);  //turn off fresh saltwater, pump water in
      ReefAngel.Relay.Override(Box1_Port3,2);  //turn off Auto Water Change mode
    }
    
    /* Override test port 
    static unsigned long AutoWaterChange;
    if (ReefAngel.Relay.isMaskOn(Box2_Port3)) AutoWaterChange=now();*/
     
    
    /* Vortech nutrient transport mode (after feeding mode)  
       Turn off nutrient transport mode */
    static unsigned long FeedTime;
    if (ReefAngel.DisplayedMenu==FEEDING_MODE) FeedTime=now();
 /* 
    if (now()-FeedTime>0 && now()-FeedTime<3600)
    {
      // Continue NTM for the 60 minutes
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Smart_NTM,155,5);
    }
              
    
    /* Vortech night mode 
     Info: you can do ReefAngel.Relay.Status(Port2); which will return 0 (off) or 1 (on) 
     In this case, my Port 2 is the refurium light. If the refugium light is on, I want
     night mode on the Vortechs on, else off
    // Turn off Night Mode
    if (ReefAngel.Relay.Status( Port2 )== 0 && ReefAngel.RF.Mode==Night) 
      ReefAngel.RF.SetMode(Night_Stop,0,0);
    // Turn on Night Mode if Fuge light is on (Fuge comes on at night)
    if (ReefAngel.Relay.Status( Port2 )== 1 && ReefAngel.RF.Mode!=Night) 
      ReefAngel.RF.SetMode(Night,20,0);
      
      */
}

Re: Alex's 75 gallon mostly automated tank

Posted: Tue Sep 18, 2012 2:34 am
by pilonstar
Really well done! How do you find the moon cycle with the radion?
Do you know if using that long the royal blue would short the leds life?
Thanks for sharing.
:)

Re: Alex's 75 gallon mostly automated tank

Posted: Tue Sep 18, 2012 10:25 am
by ScottT
alexwbush wrote:Unfortunately they don't make a glass roomba yet, so I am still involved there.
Not sure if they are available yet, but close!
http://robosnail.com/about.html

Re: Alex's 75 gallon mostly automated tank

Posted: Tue Sep 18, 2012 12:40 pm
by lnevo
pilonstar wrote:Really well done! How do you find the moon cycle with the radion?
Do you know if using that long the royal blue would short the leds life?
Thanks for sharing.
:)
MoonPhase is part of the libraries...

Code: Select all

ReefAngel.RF.SetChannel( Radion_RoyalBlue, MoonPhase() );
His code has the following check to turn on the moonlights at the right time with:

Code: Select all

   if ( (hour() < starthr && (minute() < startmin || startmin == 0) ) || (hour() > endhr && minute() > endmin) ) // If time time is before or after normal daylight cycle
      ReefAngel.RF.SetChannel( Radion_RoyalBlue, MoonPhase() ); // Run moonphase on RoyalBlue    
    else // Or else...
    {
      ReefAngel.RF.SetChannel( Radion_RoyalBlue, PWMParabola(starthr,startmin,endhr,endmin,0,intensity,0) ); // Run day cycle parabola
      ReefAngel.Relay.On(Port4); // And turn on the Vortech
    }

Re: Alex's 75 gallon mostly automated tank

Posted: Tue Sep 18, 2012 5:01 pm
by alexwbush
I don't think it would shorten the LED life enough to matter when you're probably going to dump or replace the light in 10-15 years max.

I have to test the moonlights, but I think it should run perfectly. Next task on that project is to work with the lat and long code lnevo is working on. I am trying to make it as easy as possible so new people can just copy and paste the code they want instead of hunting through mine to find it. I am a little stuck right now unfortunately since I cannot test without my RA+ board. The RF expansion takes up too much room to run with my regular RA board and the RA+ is 6 hours north. Looks like progress may slow until end of October.

But to add to the challenge... I am leave my tank for 5 whole weeks with no regular supervision. Yup, remember when I said I wanted to automate... this is part of why. I will be 2-3 hrs north, but will monitor with webcam, android app, and RA portal. Hardest part of this process... I don't have a 25 gallon RO top off container. I am considering daisy chaining 5-6 5 gallon buckets into siphoning water to the primary top off container when low. And that's not even technology! Just siphons.

Re: Alex's 75 gallon mostly automated tank

Posted: Tue Sep 18, 2012 7:30 pm
by alexwbush
ScottT wrote:
alexwbush wrote:Unfortunately they don't make a glass roomba yet, so I am still involved there.
Not sure if they are available yet, but close!
http://robosnail.com/about.html
hahahahhaha! That thing is $300. I think for that I could hire a maid for years just to clean the glass.

Alex's 75 gallon mostly automated tank

Posted: Tue Sep 18, 2012 7:35 pm
by lnevo
Just think how clean that webcam view would be for that remote tank ;)

I was a big automation junkie awhile back in doing home theater, lighting, IR, etc. I tried playing with x10 initially and then I found RA... All downhill from there :)

Re: Alex's 75 gallon mostly automated tank

Posted: Tue Sep 18, 2012 11:09 pm
by alexwbush
yeah, my dad used to work for a home automation company and I knew tons about home automation including x10. I still have a bunch of those lying around the house.

if-then-else statements can solve the world's problems haha

Re: Alex's 75 gallon mostly automated tank

Posted: Wed Sep 19, 2012 9:27 pm
by jsclownfish
alexwbush wrote:
ScottT wrote:
alexwbush wrote:Unfortunately they don't make a glass roomba yet, so I am still involved there.
Not sure if they are available yet, but close!
http://robosnail.com/about.html
hahahahhaha! That thing is $300. I think for that I could hire a maid for years just to clean the glass.
They are totally missing the mark with these. I always thought it would be really cool to have the functionality to "drive" a webcam around the tank to look at whatever I wanted. It's all possible, even with the arduino system, I just don't have the electronic chops to build it myself. :ugeek: Looks like they figured out the hard parts just need to hook on a camera.

Maybe that could be a future add-on to the RA. :D

-Jon

Re: Alex's 75 gallon mostly automated tank

Posted: Mon Sep 24, 2012 9:56 pm
by alexwbush
Added the water level expansion today! This thing is awesome!
Image
And check out the graph:
http://forum.reefangel.com/status/chart ... &filter=WL

Added some code using 2 memory slots so that I can adjust it remotely with the android app. Until the new function is available, this is how I did it...

Add this global variable:

Code: Select all

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

byte topofflevel;

////// Place global variable code above here
And add this custom code:

Code: Select all

  /* Water level ATO
     Using memory locations:
     Location 258 (ATO Level Min Value)
     Location 259 (ATO Level Max Value)
     
     **NOTE: I am using the memory locations used on the PWM expansion module, so if you
     are using the PWM expansin module, I recommend you use another memory location.
     
     If the current water level is below the ATO Level Min Value, top off until
     you reach ATO Level Max Value, else don't.
     
     Also, if the current water level falls below the measureable amount (0) turn off
     the return and skimmer.
  */
  
  if (ReefAngel.WaterLevel.GetLevel()<topofflevel)
  {
     topofflevel=InternalMemory.read(259);
     ReefAngel.Relay.On(Port5);
  }
  else
  {
     topofflevel=InternalMemory.read(258);
     ReefAngel.Relay.Off(Port5);
  }
  // If water level equals 0, turn off return relay; else, keep it on  
  if (ReefAngel.WaterLevel.GetLevel()==0)
  {
     ReefAngel.Relay.Off(Port7);
     ReefAngel.Relay.Off(Port8);
  }
  else
  {
     ReefAngel.Relay.On(Port8);
     ReefAngel.Relay.DelayedOn( Port7 );
  }

Re: Alex's 75 gallon mostly automated tank

Posted: Mon Sep 24, 2012 10:01 pm
by rimai
Pretty cool and nice mount work!!!
I didn't even bother mounting mine... lol
Mine fit really nicely between the bubble trap walls :)

Re: Alex's 75 gallon mostly automated tank

Posted: Mon Sep 24, 2012 10:33 pm
by alexwbush
Haha, thanks. I got a little lazy and used a float switch mount I wasn't using. It has been reborn a water level holder. Roberto, also something strange I found... I struggled using memory locations 1000 and 1001. They just wouldn't reflect in my unit when set. I had no problem when I decided to use the memory locations used on the dimming expansion. Not sure why.

Image

Re: Alex's 75 gallon mostly automated tank

Posted: Tue Oct 09, 2012 5:53 pm
by alexwbush
I've been running about a week and a half so far. Only issues I've had:
10/3 Vortech wet side magnet disconnected from dry side
10/8 Water level expansion strayed a bit. I have my friend some over and jiggle it around, works great again.

I have a friend watching the tank who knows nothing about saltwater and I'll be home to check on it in a little less than 2 weeks now.

Re: Alex's 75 gallon mostly automated tank

Posted: Sat Aug 31, 2013 9:37 am
by alexwbush
Ok, long overdue for an update. I'll try to post pics soon!

8/19 Added a BRS dual reactor for GFO and carbon
8/19 Added a BRS bio pellet reactor
8/19 Started messing with my RA dosing pumps. I also bought the dosing kit from BRS

I am trying to figure out how to get rid of small white particles in my water column. I think I might end up having to replace the substrate in the display. It might be too fine and I think it's being kicked up by the goby and other bottom dwellers.

Re: Alex's 75 gallon mostly automated tank

Posted: Sat Aug 31, 2013 10:51 am
by rimai
You should first figure out what they are.
Could be coming from your 2 part too, which is a bad thing :(
Low mag would cause that precipitation. Google the chemical reaction that happens when those chemical hit the water.

Re: Alex's 75 gallon mostly automated tank

Posted: Sun Feb 22, 2015 11:39 pm
by alexwbush
Better last than never. Updating my code. I cannot get Radions to work at this time. It's a known issue with the latest firmware on Radions. If you have any suggestions, please let me know. I just coded an auto water change where I replace ~5 gallons automatically once setup. Also updated my entire code on the first page. There are still a lot of testing lines in there edited out. :lol:

Code: Select all

    /* Automatic water change
    Trigger by Box2_Port3 (fake relay) that can be triggered by portal or RA app. Will turn on waste pump in sump is water
    level is above low sump level (memory location 340) or if waste bucket is full. Then will turn off waste pump and turn on
    fresh water pump to pump in water until sump water level is returned to normal. Meanwhile, return, skimmer, and heater
    should continue to operate normally.
    
    Utilized ports:
     Port 4       ATO: toggled off in auto water change
     Box1_Port5   Skimmer: will not exit mode unless skimmer is on (to account for lower water level when on)
     Box1_Port6   Sump light: toggled on in auto water change
     Box1_Port7   Waste water pump: Maxijet 1200 located in sump with drain hose to waste bucket
     Box1_Port8   Fresh water pump: 
     Box2_Port3   Auto Water Change trigger: fake relay box used for setting various "modes"
    
    Variables:
     WaterLevel.GetLevel(0)    Water level sensor in pump: Returns a value 0-100+
     HighATO.IsActive()        Float switch on waste bucket: Returns a value to indicate whether float switch is on bottom or floating
    
    Memory locations:
     Location 331   (ATO Level Low Value set @ 62)
     Location 332   (ATO Level High Value) (NOT UTILIZED, but could be helpful for changes)
     
     Location 340   (Water Level 1 Min Value -> Used for low water level in sump... set @ 25)
     */
    
    byte topofflevel=InternalMemory.read(332);
    byte sumplowlevel=InternalMemory.read(340);
    if (ReefAngel.Relay.Status(Box2_Port3)==1)
    {
      ReefAngel.Relay.Override(Box1_Port6, 1); //turn on sump light
      ReefAngel.Relay.Override(Port4, 0); //turn off ATO
      /* Drain waste water from sump if:
         1. Water level is above the low sump level (Location 340/"Water Level 1 Min Value")
         2. AND the ATO high level is not met (waste bucket NOT full)
         3. AND water fill is not on */
      if (ReefAngel.WaterLevel.GetLevel(0) > sumplowlevel && ReefAngel.HighATO.IsActive() && ReefAngel.Relay.Status(Box1_Port8)==0) 
      {
        ReefAngel.Relay.On(Box1_Port7); //turn on drain/waste pump
      }
      else ReefAngel.Relay.Off(Box1_Port7); //turn off drain/waste pump
      /* End waste water */
  
      /* Fill with fresh salt water if:
         1. Water level is below normal high level of autotop off (Location 332/"ATO Level High Value")
         2. AND waste pump is not on
         3. AND skimmer is on (to account for water level difference) */
      if (ReefAngel.WaterLevel.GetLevel(0) < topofflevel && ReefAngel.Relay.Status(Box1_Port7)==0 && ReefAngel.Relay.Status(Box1_Port5)==1)
      {
        ReefAngel.Relay.On(Box1_Port8); //turn on drain/waste pump
      }
      else ReefAngel.Relay.Off(Box1_Port8); //turn off fresh saltwater pump
      /* End clean water fill */
      
      /* Exit auto water change (make Box2_Port3 auto) if:
         1. Waste pump is off
         2. AND fresh water pump is off */
      if (ReefAngel.Relay.Status(Box1_Port7)==0 && ReefAngel.Relay.Status(Box1_Port8)==0)
      {
        ReefAngel.Relay.Override(Box2_Port3, 2); //auto water change back to auto
      }
    }
    
    else
    {
      ReefAngel.Relay.Override(Box1_Port6, 2); //auto sump light
      ReefAngel.Relay.Override(Port4, 2); //auto ATO  
    }