AlanM's INO

Share you PDE file with our community
Post Reply
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

AlanM's INO

Post by AlanM »

Here's my current code. Did up a custom display. I'm using the /dev branch of the ReefAngel code with some extra for the 16 channel PWM expansion that I haven't done a pull request for yet.

I have 4 powerheads facing each other on the two sides, back left, back right, front left, front right. I set up a custom variable for the sync mode that lets me switch if they alternate side2side, front2back, diagonally (to do gyre flow), or all on sync.

The big number to the right of the pumps on top is the current pump threshold set. Mine will normally be 30 since I have Tunze powerheads.

The black speck is a piece of dirt that somehow got underneath the sticker on the front.

I have 6 LED channels, violet, royal blue, neutral white, cool blue, deep red, cyan. The current percents are shown on the display.

Image

Update 9/4/2014: Added code to turn on alk doser when I shove a number into a custom variable in ppm carbonate as read from hanna checker. I aim for 150ppm or 3.0meq/l alkalinity, so this will run the doser a calculated amount to reach that number and then clear out the custom variable and shut it off. I would like to do the negative one which would override the doser port to off for some amount of normal dosing time to lower it, but haven't done that math yet.

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
unsigned long offtime = 0UL;
unsigned long alktime = 0UL;

void DrawCustomMain() 
{
  // want to add dosing status, and 6 PWM channels of lights
  byte pumpmode = InternalMemory.DCPumpMode_read();
  byte threshold = InternalMemory.DCPumpThreshold_read();
  byte syncmode = ReefAngel.CustomVar[0];

  if      (pumpmode ==  0) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5," Constant  ");
  else if (pumpmode ==  1) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"  Lagoon   ");
  else if (pumpmode ==  2) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"Reef Crest ");
  else if (pumpmode ==  3) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"Short Pulse");
  else if (pumpmode ==  4) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"Long Pulse ");
  else if (pumpmode ==  5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"Nutr Trans ");
  else if (pumpmode ==  6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"Tidal Swell");
  else if (pumpmode == 12) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"   Else    ");
  else if (pumpmode == 13) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"   Sine    ");
  else if (pumpmode == 14) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,DefaultBGColor,10,5,"   Gyre    ");
  
  if      (syncmode == 0) ReefAngel.LCD.DrawLargeText(COLOR_BLACK, DefaultBGColor,10,15,"Side2Side ");
  else if (syncmode == 1) ReefAngel.LCD.DrawLargeText(COLOR_BLACK, DefaultBGColor,10,15," AllSync  ");
  else if (syncmode == 2) ReefAngel.LCD.DrawLargeText(COLOR_BLACK, DefaultBGColor,10,15,"Front2Back");
  else if (syncmode == 3) ReefAngel.LCD.DrawLargeText(COLOR_BLACK, DefaultBGColor,10,15,"   Gyre   ");
  else                    ReefAngel.LCD.DrawLargeText(COLOR_BLACK, DefaultBGColor,10,15," Unknown  ");

  // draw threshold number
  char text[3];
  ConvertNumToString(text,threshold,1);
  ReefAngel.LCD.Clear(DefaultBGColor, 100,8, 126, 24);
  ReefAngel.LCD.DrawHugeText(COLOR_RED, DefaultBGColor, 100,8,text,Num12x16);
  
  DrawPumpBlock(15,25);
  DrawLEDBlock(9,45);
  DrawCustomMonitor(15,97);
  
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 107, TempRelay);
  
  ReefAngel.LCD.DrawDate(6,122);
}

void DrawLEDBlock(byte x, byte y) {
  ReefAngel.LCD.Clear(COLOR_PURPLE, x, y, x+19, y+9);
  ReefAngel.LCD.DrawText(COLOR_WHITE,COLOR_PURPLE,x+1,y+1,ReefAngel.PWM.Get16ChannelValue(2));
  ReefAngel.LCD.Clear(COLOR_NAVY, x+19, y, x+38, y+9);
  ReefAngel.LCD.DrawText(COLOR_WHITE,COLOR_NAVY,x+20,y+1,ReefAngel.PWM.Get16ChannelValue(3));
  ReefAngel.LCD.Clear(COLOR_ANTIQUEWHITE, x+38, y, x+57, y+9);
  ReefAngel.LCD.DrawText(COLOR_BLACK,COLOR_ANTIQUEWHITE,x+39,y+1,ReefAngel.PWM.Get16ChannelValue(4));
  ReefAngel.LCD.Clear(COLOR_BLUE, x+57, y, x+76, y+9);
  ReefAngel.LCD.DrawText(COLOR_WHITE,COLOR_BLUE,x+58,y+1,ReefAngel.PWM.Get16ChannelValue(5));
  ReefAngel.LCD.Clear(COLOR_CRIMSON, x+76, y, x+95, y+9);
  ReefAngel.LCD.DrawText(COLOR_WHITE,COLOR_CRIMSON,x+77,y+1,ReefAngel.PWM.Get16ChannelValue(6));
  ReefAngel.LCD.Clear(COLOR_DARKTURQUOISE, x+95, y, x+117, y+9);
  ReefAngel.LCD.DrawText(COLOR_BLACK,COLOR_DARKTURQUOISE,x+96,y+1,ReefAngel.PWM.Get16ChannelValue(7));
}

void DrawPumpBlock(byte x, byte y) {
  //left pumps
  ReefAngel.LCD.DrawText(DPColor,DefaultBGColor,x,y,"BL:");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetActinicValue(), DPColor, x+18, y,1);
  ReefAngel.LCD.DrawText(APColor,DefaultBGColor,x,y+10,"FL:");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.Get16ChannelValue(0), APColor, x+18, y+10,1);
  // right pumps
  ReefAngel.LCD.DrawText(DPColor,DefaultBGColor,x+60,y,"BR:");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+78, y,1);
  ReefAngel.LCD.DrawText(APColor,DefaultBGColor,x+60,y+10,"FR:");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.Get16ChannelValue(1), APColor, x+78, y+10,1);
}

void DrawCustomMonitor(byte x, byte y) {
    // left column
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,x,y,"T1:");
    ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T1_PROBE], T1TempColor, x+18, y,10);
    // right column 
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,x+60,y,"PH:");
    ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.PH, PHColor, x+78, y,100);
}

void DrawCustomGraph()
{
  ReefAngel.LCD.DrawGraph(5,55);
}
////// 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 
  // Ports toggled in Feeding Mode
  ReefAngel.FeedingModePorts = Port6Bit;
  // Ports toggled in Water Change Mode
  ReefAngel.WaterChangePorts = 0;
  // Ports toggled when Lights On / Off menu entry selected
  ReefAngel.LightsOnPorts = Port3Bit;
  // Ports turned off when Overheat temperature exceeded
  ReefAngel.OverheatShutoffPorts = Port1Bit;
  // Use T1 probe as temperature and overheat functions
  ReefAngel.TempProbe = T1_PROBE;
  ReefAngel.OverheatProbe = T1_PROBE;
  // Add support for 16 channel PWM board
  ReefAngel.Add16ChPWM();
  // Set the Overheat temperature setting
  InternalMemory.OverheatTemp_write( 830 );

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

  // Ports that are always on
  ReefAngel.Relay.On( Port5 );
  ReefAngel.Relay.On( Port6 );

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

  //Custom Port Labels
  ReefAngel.CustomLabels[0]="Heater"; 
  ReefAngel.CustomLabels[1]="Skimmer"; 
  ReefAngel.CustomLabels[2]="Unused"; 
  ReefAngel.CustomLabels[3]="Unused"; 
  ReefAngel.CustomLabels[4]="Return"; 
  ReefAngel.CustomLabels[5]="PowerHeads"; 
  ReefAngel.CustomLabels[6]="Alkdoser"; 
  ReefAngel.CustomLabels[7]="Caldoser";  

  // so portal always shows custom variables
  ReefAngel.CustomVar[7]=255;

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

 Want to use one float valve port for skimmate locker
 
 Relay Ports:
 1 = Heater
 2 = Skimmer
 3 = Unused
 4 = Unused
 5 = Reeflo Return
 6 = Powerheads, 2xTunze 2xJebao
 7 = Alkdoser
 8 = CalDoser
 
 DC Pumps:
 Actinic: Tunze Left
 Daylight: Tunze Right
 
 CustomDimmer: // Want lights with sinusoidal ramp up and down with center at 1pm starting and ending at 7am/7pm
 // want Jebaos to operate in conjunction with Tunzes some of the time and opposite some of the time, so sometimes it will be 
 // pushing water at each other, sometimes it will be turning a gyre back and forth.
 0 = Jebao Left
 1 = Jebao Right
 2 = Violet
 3 = Royal Blue
 4 = White
 5 = Cool Blue
 6 = Deep Red
 7 = Cyan
 8 = PWM fans
 
 */
void loop()
{
  //ReefAngel.PWM.SIXTEENChExpansionSetPercent(0); // initialize stuff to 0 at the beginning of the loop
  ReefAngel.StandardHeater( Port1 ); 
  ReefAngel.Relay.DelayedOn( Port2 ); // skimmer delay
  if (ReefAngel.Params.PH < 850) {
    ReefAngel.DosingPumpRepeat1( Port7 ); // alk doser
    adjustAlk();
  } else {
    ReefAngel.Relay.Off(Port7);  // turn it off if the pH is too high
  }
  ReefAngel.DosingPumpRepeat2( Port8 ); // cal doser
  ReefAngel.DCPump.UseMemory = true;
  ////// Place your custom code below here

  // pumps
  setPowerheadModes(ReefAngel.CustomVar[0]);
  if (ReefAngel.CustomVar[1]==0) { // then we should use these settings.  If it's 0 we should do what the portal says.  Set customvar[1] to 0 to not change like this
                                   // and use a constant profile as set by the static internal memory instead
    if ((hour() >= 13) && (hour() <= 16)) { // reef crest from 1 to 5
      InternalMemory.DCPumpMode_write(2);  
      InternalMemory.DCPumpSpeed_write(50);
      InternalMemory.DCPumpDuration_write(120);
    } else if ((hour() >= 17) && (hour() <= 19)) { // nutrient transport from 5 to 8
      InternalMemory.DCPumpMode_write(5);  
      InternalMemory.DCPumpSpeed_write(70);
      InternalMemory.DCPumpDuration_write(120);
    } else if ((hour() >= 8) && (hour() <= 12)) { // gyre from 8 to 1
      InternalMemory.DCPumpMode_write(14);  
      InternalMemory.DCPumpSpeed_write(70);
      InternalMemory.DCPumpDuration_write(4);
    } else {
      InternalMemory.DCPumpMode_write(0);  // Constant the rest of the time
      InternalMemory.DCPumpSpeed_write(30);
      InternalMemory.DCPumpDuration_write(120);
    }
  } else { // we have fixed it to some number and set the custom variable to make it stick first.
  }
  
  // lights
  ReefAngel.PWM.SIXTEENChannelPWMSigmoid(2,0,InternalMemory.PWMSlopeEnd0_read()); // Violet channel, startpwm, endpwm, offsets
  ReefAngel.PWM.SIXTEENChannelPWMSigmoid(3,0,InternalMemory.PWMSlopeEnd1_read()); // Royal Blue channel, startpwm, endpwm, offsets
  ReefAngel.PWM.SIXTEENChannelPWMSigmoid(4,0,InternalMemory.PWMSlopeEnd2_read()); // White channel, startpwm, endpwm, offsets
  ReefAngel.PWM.SIXTEENChannelPWMSigmoid(5,0,InternalMemory.PWMSlopeEnd3_read(),-30,-30); // Cool Blue channel, startpwm, endpwm, offsets
  ReefAngel.PWM.SIXTEENChannelPWMSigmoid(6,0,InternalMemory.PWMSlopeEnd4_read(),-60,-60); // Deep Red channel, startpwm, endpwm, offsets
  ReefAngel.PWM.SIXTEENChannelPWMSigmoid(7,0,InternalMemory.PWMSlopeEnd5_read(),-60,-60); // Cyan channel, startpwm, endpwm, offsets
  ReefAngel.PWM.SIXTEENChannelPWMSigmoid(8,0,75); // Fan channel, silent up to 75 or so.

  // Turn off Skimmer if Locker is full
  if(ReefAngel.HighATO.IsActive())
  {
    ReefAngel.Relay.On(Port2);
  }
  else
  {
    ReefAngel.Relay.Off(Port2);
  }
  
  // Turn off things if the power goes out
  if(ReefAngel.LowATO.IsActive())
  { // then power is on
    if (offtime > 0) { // then power was off 
      ReefAngel.Relay.On(Port2);
      ReefAngel.Relay.On(Port5);
      offtime = 0UL;
    }
  } 
  else
  { // then power is off
    // turn off lights, skimmer, return pump after two minutes, to conserve power for powerheads
    if (offtime == 0) offtime = now();
    if ((now() - offtime) > 120) { // it has been off for two minutes
      ReefAngel.Relay.Off(Port2); // turn off skimmer
      ReefAngel.Relay.Off(Port5); // turn off return pump
    }
  }

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

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

void setPowerheadModes(byte syncModeIn)
{
  switch (syncModeIn) {
  case 0:  // side to side anti-sync
    ReefAngel.DCPump.ActinicChannel = AntiSync; // Tunze Left
    ReefAngel.DCPump.DaylightChannel = Sync;    // Tunze Right
    ReefAngel.DCPump.SIXTEENChExpansionChannel[0] = AntiSync; // Jebao Left
    ReefAngel.DCPump.SIXTEENChExpansionChannel[1] = Sync;     // Jebao Right
    break;
  case 1: // all on sync
    ReefAngel.DCPump.ActinicChannel = Sync;   // Tunze Left
    ReefAngel.DCPump.DaylightChannel = Sync;  // Tunze Right
    ReefAngel.DCPump.SIXTEENChExpansionChannel[0] = Sync; // Jebao Left
    ReefAngel.DCPump.SIXTEENChExpansionChannel[1] = Sync; // Jebao Right
    break;
  case 2: // front/back sync
    ReefAngel.DCPump.ActinicChannel = Sync;   // Tunze Left
    ReefAngel.DCPump.DaylightChannel = Sync;  // Tunze Right
    ReefAngel.DCPump.SIXTEENChExpansionChannel[0] = AntiSync; // Jebao Left
    ReefAngel.DCPump.SIXTEENChExpansionChannel[1] = AntiSync; // Jebao Right
    break;
  default: // gyre flow, diagonal sync
    ReefAngel.DCPump.ActinicChannel = AntiSync; // Tunze Left
    ReefAngel.DCPump.DaylightChannel = Sync;    // Tunze Right
    ReefAngel.DCPump.SIXTEENChExpansionChannel[0] = Sync;     // Jebao Left
    ReefAngel.DCPump.SIXTEENChExpansionChannel[1] = AntiSync; // Jebao Right
    break;
  }
}

void adjustAlk() {
  // check to see if extra alk was requested
  // CustomVar is the value read on the checker
    if (ReefAngel.CustomVar[2] > 0) {
      int alkneeded = 150 - ReefAngel.CustomVar[2];
      float onTime = 0;
      if (alkneeded > 0) {
        onTime = 3.64*(float)alkneeded; // onTime is minutes to run, for 110 gallons volume, 1ppm is 4.4ml and 1.21ml/min, so 3.64 minutes per ppm of alk.
      } else {
        ReefAngel.CustomVar[2] = 0; // else it must be either negative or at 150, so reset and do nothing.
        return;
      }
      if (alktime == 0) { // it must have just gotten noticed
        alktime = now()+(onTime*60UL); // should get rounded to integer seconds here
        ReefAngel.Relay.On(Port7); // set it to on
      } else if (now() > alktime) {
        //ReefAngel.Relay.Override(Port7,2);  // set it back to auto, clear the override
        ReefAngel.Relay.Off(Port7); // turn it off
        ReefAngel.CustomVar[2] = 0; // clear the custom variable
        alktime = 0; // set alktime back to 0
      } else { // must be less than alktime, so keep it on
        ReefAngel.Relay.On(Port7);
      }
    } else {
      return;
    }
}
Post Reply