water change build

Do you have a question on how to do something.
Ask in here.
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

water change build

Post by tyson_mitchell_88 »

Hi all, I would like some help to write some Script for a water change setup. If this sounds out of wack let me know. Just trying to use what I have available.

At 6pm every day the following to occur

>box1 port 7 & 8 to turn off
>Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
>turn on box 1 port 7 & 8
>run box 1 port 1 until ato high is on for 10 mins (Salt In)
>return to usual

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 <Moon.h>

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


//Standard Dimming//
byte ActinicPWMValue=0;    // For cloud code
byte DaylightPWMValue=0;   // For cloud code

//Dimmer Expansion//
byte WhitePWMValue=0;
byte SupPWMValue=0;
byte MoonPWMValue=0;

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


void setup()
{
    InternalMemory.LCDID_write(0);
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    ReefAngel.SetTemperatureUnit( Celsius );  // set to Celsius Temperature

    ReefAngel.Use2014Screen();  // Let's use 2014 Screen 
    ReefAngel.AddSalinityExpansion();  // Salinity Expansion Module
    ReefAngel.AddORPExpansion();  // ORP Expansion Module
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = 0;
    ReefAngel.FeedingModePortsE[0] = Port7Bit | Port8Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = 0;
    ReefAngel.WaterChangePortsE[0] = Port7Bit | Port8Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    ReefAngel.LightsOnPortsE[0] = 0;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = 0;
    ReefAngel.OverheatShutoffPortsE[0] = 0;
    // 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(Port6);
    ReefAngel.Relay.On(Box1_Port6);
    ReefAngel.Relay.On(Box1_Port7);

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

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

void loop()
{
    ReefAngel.StandardHeater( Port2,220,225 );
    ReefAngel.StandardLights( Port3,8,00,16,00);
    ReefAngel.StandardFan   ( Port4,230,238 );
    ReefAngel.StandardLights( Port7,21,00,5,00 );
    ReefAngel.StandardLights( Port8,5,00,21,00 );
    
    ReefAngel.StandardLights( Box1_Port5,8,00,16,00 );
        
    ////// Place your custom code below here
 

//Display in Failsafe//
    if (ReefAngel.LowATO.IsActive())
      ReefAngel.Relay.On(Box1_Port8);
    else
      ReefAngel.Relay.Off(Box1_Port8);
  
//boosterpump//
    if (ReefAngel.LowATO.IsActive())
      ReefAngel.Relay.Off(Box1_Port2);
    else
      ReefAngel.Relay.On(Box1_Port2);

  
//Lighting Control//

    ActinicPWMValue=PWMSlope(5,00,21,00,0,100,180,ActinicPWMValue);
    DaylightPWMValue=PWMSlope(6,30,18,30,0,70,180,DaylightPWMValue);
    WhitePWMValue=PWMSlope(6,30,18,30,0,60,180,WhitePWMValue);
    SupPWMValue=PWMSlope(8,00,16,00,0,80,200,SupPWMValue);
    MoonPWMValue=PWMSlope(21,00,5,00,0,30,235,0); 
    CheckCloud();
    ReefAngel.PWM.SetActinic(ActinicPWMValue);
    ReefAngel.PWM.SetDaylight(DaylightPWMValue);    
    
//Lighting expansion control//

    ReefAngel.PWM.SetChannel( 0, WhitePWMValue); 
    ReefAngel.PWM.SetChannel( 1, ActinicPWMValue);
    ReefAngel.PWM.SetChannel( 2, SupPWMValue);
    ReefAngel.PWM.SetChannel( 3, SupPWMValue);
    ReefAngel.PWM.SetChannel( 4, MoonPWMValue);
    ReefAngel.PWM.SetChannel( 5, MoonPWMValue);

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

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

void CheckCloud()
{

  // ------------------------------------------------------------
  // Change the values below to customize your cloud/storm effect

  // Frequency in days based on the day of the month - number 2 means every 2 days, for example (day 2,4,6 etc)
  // For testing purposes, you can use 1 and cause the cloud to occur everyday
#define Clouds_Every_X_Days 1 

  // Percentage chance of a cloud happening today
  // For testing purposes, you can use 100 and cause the cloud to have 100% chance of happening
#define Cloud_Chance_per_Day 100

  // Minimum number of minutes for cloud duration.  Don't use max duration of less than 6
#define Min_Cloud_Duration 7

  // Maximum number of minutes for the cloud duration. Don't use max duration of more than 255
#define Max_Cloud_Duration 20

  // Minimum number of clouds that can happen per day
#define Min_Clouds_per_Day 3

  // Maximum number of clouds that can happen per day
#define Max_Clouds_per_Day 10

  // Only start the cloud effect after this setting
  // In this example, start cloud after noon
#define Start_Cloud_After NumMins(6,30)

  // Always end the cloud effect before this setting
  // In this example, end cloud before 9:00pm
#define End_Cloud_Before NumMins(18,30)

  // Percentage chance of a lightning happen for every cloud
  // For testing purposes, you can use 100 and cause the lightning to have 100% chance of happening
#define Lightning_Change_per_Cloud 60

  // Note: Make sure to choose correct values that will work within your PWMSLope settings.
  // For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
  // Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes of effects or unforseen results could happen.
    // Also, make sure that you can fit double those minutes between Start_Cloud_After and End_Cloud_Before.
  // In our example, we have 510 minutes between Start_Cloud_After and End_Cloud_Before, so double the 250 minutes (or 500 minutes) can fit in that 510 minutes window.
    // It's a tight fit, but it did.

    //#define printdebug // Uncomment this for debug print on Serial Monitor window
#define forcecloudcalculation // Uncomment this to force the cloud calculation to happen in the boot process. 

    // Add Random Lightning modes
#define Calm 0    // No lightning
#define Slow 1    // 5 seconds of slow lightning in the middle of a cloud for ELN style (slow response) drivers
#define Fast 2    // 5 seconds of fast lightning in the middle of a cloud for LDD style (fast response) drivers
#define Mega 3    // Lightning throughout the cloud, higher chance as it gets darker
#define Mega2 4   // Like Mega, but with more lightning
  // Set which modes you want to use
  // Example:  { Slow, Fast, Mega, Mega2 } to randomize all four modes.  
  // { Mega2 } for just Mega2.  { Mega, Mega, Fast} for Mega and Fast, with twice the chance of Mega.
  byte LightningModes[] = { Calm, Calm, Calm, Slow, Slow, Slow, Slow, Slow, Mega, Mega2 };

  // Change the values above to customize your cloud/storm effect
  // ------------------------------------------------------------
  // Do not change anything below here

   static byte cloudchance=255;
  static byte cloudduration=0;
  static int cloudstart=0;
  static byte numclouds=0;
  static byte lightningchance=0;
  static byte cloudindex=0;
  static byte lightningstatus=0;
  static int LastNumMins=0;
  static byte lightningMode=0;
  static boolean chooseLightning=true;

  static time_t DelayCounter=millis();    // Variable for lightning timing.  
  static int DelayTime=random(1000);      // Variable for lightning timimg.

  // Every day at midnight, we check for chance of cloud happening today
  if (hour()==0 && minute()==0 && second()==0) cloudchance=255;

#ifdef forcecloudcalculation
  if (cloudchance==255)
#else
    if (hour()==0 && minute()==0 && second()==1 && cloudchance==255) 
#endif
    {
      randomSeed(millis());    // Seed the random number generator
      //Pick a random number between 0 and 99
      cloudchance=random(100); 
      // if picked number is greater than Cloud_Chance_per_Day, we will not have clouds today
      if (cloudchance>Cloud_Chance_per_Day) cloudchance=0;
      // Check if today is day for clouds. 
      if ((day()%Clouds_Every_X_Days)!=0) cloudchance=0; 
      // If we have cloud today
      if (cloudchance)
      {
        // pick a random number for number of clouds between Min_Clouds_per_Day and Max_Clouds_per_Day
        numclouds=random(Min_Clouds_per_Day,Max_Clouds_per_Day);
        // pick the time that the first cloud will start
        // the range is calculated between Start_Cloud_After and the even distribuition of clouds on this day. 
        cloudstart=random(Start_Cloud_After,Start_Cloud_After+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0; 
      }
    }
  // Now that we have all the parameters for the cloud, let's create the effect

  if (cloudchance)
  {
        
    //is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,DaylightPWMValue,0,180);
      WhitePWMValue=DaylightPWMValue;
      MoonPWMValue=DaylightPWMValue;

      if (chooseLightning) 
      { 
        lightningMode=LightningModes[random(100)%sizeof(LightningModes)]; 
        chooseLightning=false; 
      } 
      switch (lightningMode) 
      {
      case Calm:
        break;
      case Mega:
        // Lightning chance from beginning of cloud through the end.  Chance increases with darkness of cloud.
        if (lightningchance && random(ReversePWMSlope(cloudstart,cloudstart+cloudduration,100,0,180))<1 && (millis()-DelayCounter)>DelayTime)
        {
          // Send the trigger 
          Strike();
          DelayCounter=millis();    // If we just had a round of flashes, then lets put in a longer delay
          DelayTime=random(1000);   // of up to a second for dramatic effect before we do another round. 
        }
        break;
      case Mega2:
        // Higher lightning chance from beginning of cloud through the end.  Chance increases with darkness of cloud.
        if (lightningchance && random(ReversePWMSlope(cloudstart,cloudstart+cloudduration,100,0,180))<2)
        {
          Strike();
        }
        break;
      case Fast:
        // 5 seconds of lightning in the middle of the cloud
        if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5 && (millis()-DelayCounter)>DelayTime)
        {
          Strike();

          DelayCounter=millis();    // If we just had a round of flashes, then lets put in a longer delay
          DelayTime=random(1000);   // of up to a second for dramatic effect before we do another round. 
        }
        break;
      case Slow:
        // Slow lightning for 5 seconds in the middle of the cloud.  Suitable for slower ELN style drivers
        if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
        {
          if (random(100)<20) lightningstatus=1; 
          else lightningstatus=0;
          if (lightningstatus)
          {
            DaylightPWMValue=100; 
          }
          else 
          {
            DaylightPWMValue=0;
          }
          delay(1);
        }
        break;
      default:
        break;
      }
    } 
    else 
    {
      chooseLightning=true; // Reset the flag to choose a new lightning type
    }

    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  }

  // Write the times of the next cloud, next lightning, and cloud duration to the screen and into some customvars for the Portal.
  if (LastNumMins!=NumMins(hour(),minute()))
  {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,120,132,132);
    ReefAngel.LCD.DrawText(0,255,5,120,"C");
    ReefAngel.LCD.DrawText(0,255,11,120,"00:00");
    ReefAngel.LCD.DrawText(0,255,45,120,"L");
    ReefAngel.LCD.DrawText(0,255,51,120,"00:00");
    if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
      int x=0;
      if ((cloudstart/60)>=10) x=11; 
      else x=17;
      ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart/60));
      ReefAngel.CustomVar[3]=cloudstart/60;    // Write the hour of the next cloud to custom variable for Portal reporting
      if ((cloudstart%60)>=10) x=29; 
      else x=35;
      ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
      ReefAngel.CustomVar[4]=cloudstart%60;    // Write the minute of the next cloud to custom variable for Portal reporting

    }
    ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
    ReefAngel.CustomVar[7]=(cloudduration);    // Put the duration of the next cloud in a custom var for the portal
    if (lightningchance) 
    {
      int x=0;
      if (((cloudstart+(cloudduration/2))/60)>=10) x=51; 
      else x=57;
      ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))/60));
      ReefAngel.CustomVar[5]=(cloudstart+(cloudduration/2))/60;    // Write the hour of the next lightning to a custom variable for the Portal
      if (((cloudstart+(cloudduration/2))%60)>=10) x=69; 
      else x=75;
      ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60));    // Write the minute of the next lightning to a custom variable for the Portal
      ReefAngel.CustomVar[6]=(cloudstart+(cloudduration/2))%60;
    }
  }   
}

void Strike()
{
  byte n;
  int newdata;
  byte a=random(1,5);    // Pick a number of consecutive flashes from 1 to 4.  
  for (byte i=0; i<a; i++)
  {
    // Flash on
    analogWrite(daylightPWMPin,255);    // Flash on daylight port
    
    newdata=4095;
    Wire.beginTransmission(0x40);      // Address of the dimming expansion module
    Wire.write(0x8+(4*0));             // 0x8 is channel 0, 0x12 is channel 1, etc.  I'm using channel 0.
    Wire.write(newdata&0xff);          // Send the data 8 bits at a time.  This sends the LSB
    Wire.write(newdata>>8);            // This sends the MSB
    Wire.endTransmission();
    
    
       
    int randy=random(20,80);    // Random number for a delay
    if (randy>71) randy=((randy-70)/2)*100;    // Small chance of a longer delay
    delay(randy);                // Wait from 20 to 69 ms, or 100-400 ms
    
    // Flash off.  Return to baseline.
    
    analogWrite(daylightPWMPin,DaylightPWMValue*2.55);      // Flash off

    newdata=ReefAngel.PWM.GetChannelValue(0);   // Use the channel number you're flashing here
    Wire.beginTransmission(0x40);    // Same as above
    Wire.write(0x8+(4*1));
    Wire.write(newdata&0xff);
    Wire.write(newdata>>8);
    Wire.endTransmission();
    
    
    
    delay(random(30,50));                // Wait from 30 to 49 ms 
    wdt_reset();    // Reset watchdog timer to avoid re-boots
  }
}

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
  long n=elapsedSecsToday(now());
  cstart*=60;
  cend*=60;
  if (n<cstart) return PWMStart;
  if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
  if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
  if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
  if (n>cend) return (int) PWMStart;
}
Last edited by tyson_mitchell_88 on Sat Jan 16, 2016 6:27 am, edited 2 times in total.
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Sorry haven't had a chance to get to this one yet. Hang in, will try later this week/weekend
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

All good mate. Thank you :)
Image
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

Any luck having a look at this one Lee?
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

No but its a 3 day weekend and I'll be doing some of my own coding so I should have a chance. Sorry man.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

What is Box1_Port7 and Box1_Port8? Are you sure you want them to turn back on before the return to usual?

>box1 port 7 & 8 to turn off
>Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
>turn on box 1 port 7 & 8
>run box 1 port 1 until ato high is on for 10 mins (Salt In)
>return to usual
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Try this. I wasn't sure how you wanted the 10 minutes handled. It's setup as a timeout here. Also I assumed those two ports to wait until the "return to usual".

Code: Select all

  static byte wc_start=false;
  static time_t wc_drain=0;
  static time_t wc_refill=0;
  
  if (hour()==18 && minute()==0 && !wc_start) {   // At 6pm every day the following to occur 
    wc_start==true;
    wc_drain=now()+600; 
  }
  
  if (wc_start) {
    // box1 port 7 & 8 to turn off 
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
    if (now() < wc_drain || !ReefAngel.HighATO.IsActive()) {  // Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
      ReefAngel.Relay.On(Box1_Port4);
    } else if (now() < wc_refill || ReefAngel.HighATO.IsActive()) { // run box 1 port 1 until ato high is on for 10 mins (Salt In)
      ReefAngel.Relay.Off(Box1_Port4);
      ReefAngel.Relay.On(Box1_Port1);
    } else { // return to usual
      wc_start=false;
      ReefAngel.Relay.Off(Box1_Port4);
      ReefAngel.Relay.Off(Box1_Port1);
      // turn on box 1 port 7 & 8
      ReefAngel.Relay.On(Box1_Port7);
      ReefAngel.Relay.On(Box1_Port8);
    }
  }
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

This is awesome thanks Lee. Port 7 & 8 are my tank returns so I will need them to go on before Salt In. Have amended as below. Compiles fine, now to see it in action tonight :D

Would it take much to add a trigger to active when water change mode is activated?

Code: Select all

  static byte wc_start=false;
  static time_t wc_drain=0;
  static time_t wc_refill=0;
  
  if (hour()==18 && minute()==0 && !wc_start) {   // At 6pm every day the following to occur 
    wc_start==true;
    wc_drain=now()+600; 
  }
  
  if (wc_start) {
    // box1 port 7 & 8 to turn off 
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
    if (now() < wc_drain || !ReefAngel.HighATO.IsActive()) {  // Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
      ReefAngel.Relay.On(Box1_Port4);
    } else if (now() < wc_refill || ReefAngel.HighATO.IsActive()) { // run box 1 port 1 until ato high is on for 10 mins (Salt In)
      ReefAngel.Relay.On(Box1_Port7);
      ReefAngel.Relay.On(Box1_Port8);
      ReefAngel.Relay.Off(Box1_Port4);
      ReefAngel.Relay.On(Box1_Port1);
    } else { // return to usual
      wc_start=false;
      ReefAngel.Relay.Off(Box1_Port4);
      ReefAngel.Relay.Off(Box1_Port1);
      // turn on box 1 port 7 & 8
      ReefAngel.Relay.On(Box1_Port7);
      ReefAngel.Relay.On(Box1_Port8);
    }
  }
Image
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

I have changed the time on this to test and haven't had a result. Just wanted to check that this all goes into void loop?

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 <Moon.h>

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


//Standard Dimming//
byte ActinicPWMValue=0;    // For cloud code
byte DaylightPWMValue=0;   // For cloud code

//Dimmer Expansion//
byte WhitePWMValue=0;
byte SupPWMValue=0;
byte MoonPWMValue=0;

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


void setup()
{
    InternalMemory.LCDID_write(0);
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    ReefAngel.SetTemperatureUnit( Celsius );  // set to Celsius Temperature

    ReefAngel.Use2014Screen();  // Let's use 2014 Screen 
    ReefAngel.AddSalinityExpansion();  // Salinity Expansion Module
    ReefAngel.AddORPExpansion();  // ORP Expansion Module
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = 0;
    ReefAngel.FeedingModePortsE[0] = Port7Bit | Port8Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = 0;
    ReefAngel.WaterChangePortsE[0] = Port7Bit | Port8Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    ReefAngel.LightsOnPortsE[0] = 0;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = 0;
    ReefAngel.OverheatShutoffPortsE[0] = 0;
    // 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(Port6);
    ReefAngel.Relay.On(Box1_Port6);
    ReefAngel.Relay.On(Box1_Port7);

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

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

void loop()
{
    ReefAngel.StandardHeater( Port2,220,225 );
    ReefAngel.StandardLights( Port3,8,00,16,00);
    ReefAngel.StandardFan   ( Port4,230,238 );
    ReefAngel.StandardLights( Port7,21,00,5,00 );
    ReefAngel.StandardLights( Port8,5,00,21,00 );
    
    ReefAngel.StandardLights( Box1_Port5,8,00,16,00 );
        
    ////// Place your custom code below here
 

//Display in Failsafe//
    if (ReefAngel.LowATO.IsActive())
      ReefAngel.Relay.On(Box1_Port8);
    else
      ReefAngel.Relay.Off(Box1_Port8);
  
//boosterpump//
    if (ReefAngel.LowATO.IsActive())
      ReefAngel.Relay.Off(Box1_Port2);
    else
      ReefAngel.Relay.On(Box1_Port2);

  
//Lighting Control//

    ActinicPWMValue=PWMSlope(5,00,21,00,11,100,180,ActinicPWMValue);
    DaylightPWMValue=PWMSlope(6,30,18,30,0,70,180,DaylightPWMValue);
    WhitePWMValue=PWMSlope(6,30,18,30,0,60,180,WhitePWMValue);
    SupPWMValue=PWMSlope(8,00,16,00,0,80,200,SupPWMValue);
    MoonPWMValue=PWMSlope(21,00,5,00,0,30,235,0); 
    CheckCloud();
    ReefAngel.PWM.SetActinic(ActinicPWMValue);
    ReefAngel.PWM.SetDaylight(DaylightPWMValue);    
    
//Lighting expansion control//

    ReefAngel.PWM.SetChannel( 0, WhitePWMValue); 
    ReefAngel.PWM.SetChannel( 1, ActinicPWMValue);
    ReefAngel.PWM.SetChannel( 2, SupPWMValue);
    ReefAngel.PWM.SetChannel( 3, SupPWMValue);
    ReefAngel.PWM.SetChannel( 4, MoonPWMValue);
    ReefAngel.PWM.SetChannel( 5, MoonPWMValue);
    
//Waterchange Mode    
    
  static byte wc_start=false;
  static time_t wc_drain=0;
  static time_t wc_refill=0;
  
  if (hour()==05 && minute()==30 && !wc_start) {   // At 6pm every day the following to occur 
    wc_start==true;
    wc_drain=now()+600; 
  }
  
  if (wc_start) {
    // box1 port 7 & 8 to turn off 
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
    if (now() < wc_drain || !ReefAngel.HighATO.IsActive()) {  // Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
      ReefAngel.Relay.On(Box1_Port4);
    } else if (now() < wc_refill || ReefAngel.HighATO.IsActive()) { // run box 1 port 1 until ato high is on for 10 mins (Salt In)
      ReefAngel.Relay.On(Box1_Port7);
      ReefAngel.Relay.On(Box1_Port8);
      ReefAngel.Relay.Off(Box1_Port4);
      ReefAngel.Relay.On(Box1_Port1);
    } else { // return to usual
      wc_start=false;
      ReefAngel.Relay.Off(Box1_Port4);
      ReefAngel.Relay.Off(Box1_Port1);
      // turn on box 1 port 7 & 8
      ReefAngel.Relay.On(Box1_Port7);
      ReefAngel.Relay.On(Box1_Port8);
    }
  }

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

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

void CheckCloud()
{

  // ------------------------------------------------------------
  // Change the values below to customize your cloud/storm effect

  // Frequency in days based on the day of the month - number 2 means every 2 days, for example (day 2,4,6 etc)
  // For testing purposes, you can use 1 and cause the cloud to occur everyday
#define Clouds_Every_X_Days 1 

  // Percentage chance of a cloud happening today
  // For testing purposes, you can use 100 and cause the cloud to have 100% chance of happening
#define Cloud_Chance_per_Day 100

  // Minimum number of minutes for cloud duration.  Don't use max duration of less than 6
#define Min_Cloud_Duration 7

  // Maximum number of minutes for the cloud duration. Don't use max duration of more than 255
#define Max_Cloud_Duration 20

  // Minimum number of clouds that can happen per day
#define Min_Clouds_per_Day 3

  // Maximum number of clouds that can happen per day
#define Max_Clouds_per_Day 10

  // Only start the cloud effect after this setting
  // In this example, start cloud after noon
#define Start_Cloud_After NumMins(6,30)

  // Always end the cloud effect before this setting
  // In this example, end cloud before 9:00pm
#define End_Cloud_Before NumMins(18,30)

  // Percentage chance of a lightning happen for every cloud
  // For testing purposes, you can use 100 and cause the lightning to have 100% chance of happening
#define Lightning_Change_per_Cloud 60

  // Note: Make sure to choose correct values that will work within your PWMSLope settings.
  // For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
  // Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes of effects or unforseen results could happen.
    // Also, make sure that you can fit double those minutes between Start_Cloud_After and End_Cloud_Before.
  // In our example, we have 510 minutes between Start_Cloud_After and End_Cloud_Before, so double the 250 minutes (or 500 minutes) can fit in that 510 minutes window.
    // It's a tight fit, but it did.

    //#define printdebug // Uncomment this for debug print on Serial Monitor window
#define forcecloudcalculation // Uncomment this to force the cloud calculation to happen in the boot process. 

    // Add Random Lightning modes
#define Calm 0    // No lightning
#define Slow 1    // 5 seconds of slow lightning in the middle of a cloud for ELN style (slow response) drivers
#define Fast 2    // 5 seconds of fast lightning in the middle of a cloud for LDD style (fast response) drivers
#define Mega 3    // Lightning throughout the cloud, higher chance as it gets darker
#define Mega2 4   // Like Mega, but with more lightning
  // Set which modes you want to use
  // Example:  { Slow, Fast, Mega, Mega2 } to randomize all four modes.  
  // { Mega2 } for just Mega2.  { Mega, Mega, Fast} for Mega and Fast, with twice the chance of Mega.
  byte LightningModes[] = { Calm, Calm, Calm, Slow, Slow, Slow, Slow, Slow, Mega, Mega2 };

  // Change the values above to customize your cloud/storm effect
  // ------------------------------------------------------------
  // Do not change anything below here

   static byte cloudchance=255;
  static byte cloudduration=0;
  static int cloudstart=0;
  static byte numclouds=0;
  static byte lightningchance=0;
  static byte cloudindex=0;
  static byte lightningstatus=0;
  static int LastNumMins=0;
  static byte lightningMode=0;
  static boolean chooseLightning=true;

  static time_t DelayCounter=millis();    // Variable for lightning timing.  
  static int DelayTime=random(1000);      // Variable for lightning timimg.

  // Every day at midnight, we check for chance of cloud happening today
  if (hour()==0 && minute()==0 && second()==0) cloudchance=255;

#ifdef forcecloudcalculation
  if (cloudchance==255)
#else
    if (hour()==0 && minute()==0 && second()==1 && cloudchance==255) 
#endif
    {
      randomSeed(millis());    // Seed the random number generator
      //Pick a random number between 0 and 99
      cloudchance=random(100); 
      // if picked number is greater than Cloud_Chance_per_Day, we will not have clouds today
      if (cloudchance>Cloud_Chance_per_Day) cloudchance=0;
      // Check if today is day for clouds. 
      if ((day()%Clouds_Every_X_Days)!=0) cloudchance=0; 
      // If we have cloud today
      if (cloudchance)
      {
        // pick a random number for number of clouds between Min_Clouds_per_Day and Max_Clouds_per_Day
        numclouds=random(Min_Clouds_per_Day,Max_Clouds_per_Day);
        // pick the time that the first cloud will start
        // the range is calculated between Start_Cloud_After and the even distribuition of clouds on this day. 
        cloudstart=random(Start_Cloud_After,Start_Cloud_After+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0; 
      }
    }
  // Now that we have all the parameters for the cloud, let's create the effect

  if (cloudchance)
  {
        
    //is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,DaylightPWMValue,0,180);
      WhitePWMValue=DaylightPWMValue;
      MoonPWMValue=DaylightPWMValue;

      if (chooseLightning) 
      { 
        lightningMode=LightningModes[random(100)%sizeof(LightningModes)]; 
        chooseLightning=false; 
      } 
      switch (lightningMode) 
      {
      case Calm:
        break;
      case Mega:
        // Lightning chance from beginning of cloud through the end.  Chance increases with darkness of cloud.
        if (lightningchance && random(ReversePWMSlope(cloudstart,cloudstart+cloudduration,100,0,180))<1 && (millis()-DelayCounter)>DelayTime)
        {
          // Send the trigger 
          Strike();
          DelayCounter=millis();    // If we just had a round of flashes, then lets put in a longer delay
          DelayTime=random(1000);   // of up to a second for dramatic effect before we do another round. 
        }
        break;
      case Mega2:
        // Higher lightning chance from beginning of cloud through the end.  Chance increases with darkness of cloud.
        if (lightningchance && random(ReversePWMSlope(cloudstart,cloudstart+cloudduration,100,0,180))<2)
        {
          Strike();
        }
        break;
      case Fast:
        // 5 seconds of lightning in the middle of the cloud
        if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5 && (millis()-DelayCounter)>DelayTime)
        {
          Strike();

          DelayCounter=millis();    // If we just had a round of flashes, then lets put in a longer delay
          DelayTime=random(1000);   // of up to a second for dramatic effect before we do another round. 
        }
        break;
      case Slow:
        // Slow lightning for 5 seconds in the middle of the cloud.  Suitable for slower ELN style drivers
        if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
        {
          if (random(100)<20) lightningstatus=1; 
          else lightningstatus=0;
          if (lightningstatus)
          {
            DaylightPWMValue=100; 
          }
          else 
          {
            DaylightPWMValue=0;
          }
          delay(1);
        }
        break;
      default:
        break;
      }
    } 
    else 
    {
      chooseLightning=true; // Reset the flag to choose a new lightning type
    }

    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  }

  // Write the times of the next cloud, next lightning, and cloud duration to the screen and into some customvars for the Portal.
  if (LastNumMins!=NumMins(hour(),minute()))
  {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,120,132,132);
    ReefAngel.LCD.DrawText(0,255,5,120,"C");
    ReefAngel.LCD.DrawText(0,255,11,120,"00:00");
    ReefAngel.LCD.DrawText(0,255,45,120,"L");
    ReefAngel.LCD.DrawText(0,255,51,120,"00:00");
    if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
      int x=0;
      if ((cloudstart/60)>=10) x=11; 
      else x=17;
      ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart/60));
      ReefAngel.CustomVar[3]=cloudstart/60;    // Write the hour of the next cloud to custom variable for Portal reporting
      if ((cloudstart%60)>=10) x=29; 
      else x=35;
      ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
      ReefAngel.CustomVar[4]=cloudstart%60;    // Write the minute of the next cloud to custom variable for Portal reporting

    }
    ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
    ReefAngel.CustomVar[7]=(cloudduration);    // Put the duration of the next cloud in a custom var for the portal
    if (lightningchance) 
    {
      int x=0;
      if (((cloudstart+(cloudduration/2))/60)>=10) x=51; 
      else x=57;
      ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))/60));
      ReefAngel.CustomVar[5]=(cloudstart+(cloudduration/2))/60;    // Write the hour of the next lightning to a custom variable for the Portal
      if (((cloudstart+(cloudduration/2))%60)>=10) x=69; 
      else x=75;
      ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60));    // Write the minute of the next lightning to a custom variable for the Portal
      ReefAngel.CustomVar[6]=(cloudstart+(cloudduration/2))%60;
    }
  }   
}

void Strike()
{
  byte n;
  int newdata;
  byte a=random(1,5);    // Pick a number of consecutive flashes from 1 to 4.  
  for (byte i=0; i<a; i++)
  {
    // Flash on
    analogWrite(daylightPWMPin,255);    // Flash on daylight port
    
    newdata=4095;
    Wire.beginTransmission(0x40);      // Address of the dimming expansion module
    Wire.write(0x8+(4*0));             // 0x8 is channel 0, 0x12 is channel 1, etc.  I'm using channel 0.
    Wire.write(newdata&0xff);          // Send the data 8 bits at a time.  This sends the LSB
    Wire.write(newdata>>8);            // This sends the MSB
    Wire.endTransmission();
    
    
       
    int randy=random(20,80);    // Random number for a delay
    if (randy>71) randy=((randy-70)/2)*100;    // Small chance of a longer delay
    delay(randy);                // Wait from 20 to 69 ms, or 100-400 ms
    
    // Flash off.  Return to baseline.
    
    analogWrite(daylightPWMPin,DaylightPWMValue*2.55);      // Flash off

    newdata=ReefAngel.PWM.GetChannelValue(0);   // Use the channel number you're flashing here
    Wire.beginTransmission(0x40);    // Same as above
    Wire.write(0x8+(4*1));
    Wire.write(newdata&0xff);
    Wire.write(newdata>>8);
    Wire.endTransmission();
    
    
    
    delay(random(30,50));                // Wait from 30 to 49 ms 
    wdt_reset();    // Reset watchdog timer to avoid re-boots
  }
}

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
  long n=elapsedSecsToday(now());
  cstart*=60;
  cend*=60;
  if (n<cstart) return PWMStart;
  if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
  if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
  if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
  if (n>cend) return (int) PWMStart;
}



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

Re: water change build

Post by lnevo »

Ok, try this to trigger with WC and to have return pumps go on before salt in.

Code: Select all

  static byte wc_start=false;
  static time_t wc_drain=0;
  static time_t wc_refill=0;
  
  if ((ReefAngel.DisplayedMenu==WATERCHANGE_MODE || (hour()==18 && minute()==0)) && !wc_start) {   // At 6pm every day the following to occur or when WC mode is activated
    wc_start==true;
    wc_drain=now()+600; 
  }
  
  if (wc_start) {
    // box1 port 7 & 8 to turn off 
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
    if (now() < wc_drain || !ReefAngel.HighATO.IsActive()) {  // Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
    ReefAngel.Relay.On(Box1_Port4);
    } else if (now() < wc_refill || ReefAngel.HighATO.IsActive()) { // run box 1 port 1 until ato high is on for 10 mins (Salt In)
      ReefAngel.Relay.Off(Box1_Port4);
      // turn on box 1 port 7 & 8
      ReefAngel.Relay.On(Box1_Port7);
      ReefAngel.Relay.On(Box1_Port8);
      ReefAngel.Relay.On(Box1_Port1);
    } else { // return to usual
      wc_start=false;
      ReefAngel.Relay.Off(Box1_Port4);
      ReefAngel.Relay.Off(Box1_Port1);
    }
  }
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

im not having a response from waterchange mode either.
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Try this:

Code: Select all

  static byte wc_start=false;
  static time_t wc_drain=0;
  static time_t wc_refill=0;
  
  if ((ReefAngel.DisplayedMenu==WATERCHANGE_MODE || (hour()==18 && minute()==0)) && !wc_start) {   // At 6pm every day the following to occur or when WC mode is activated
    wc_start=true;
    wc_drain=now()+600; 
  }
  
  if (wc_start) {
    // box1 port 7 & 8 to turn off 
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
    if (now() < wc_drain && ReefAngel.HighATO.IsActive()) {  // Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
    ReefAngel.Relay.On(Box1_Port4);
    } else if (now() < wc_refill && !ReefAngel.HighATO.IsActive()) { // run box 1 port 1 until ato high is on for 10 mins (Salt In)
      ReefAngel.Relay.Off(Box1_Port4);
      // turn on box 1 port 7 & 8
      ReefAngel.Relay.On(Box1_Port7);
      ReefAngel.Relay.On(Box1_Port8);
      ReefAngel.Relay.On(Box1_Port1);
    } else { // return to usual
      wc_start=false;
      ReefAngel.Relay.Off(Box1_Port4);
      ReefAngel.Relay.Off(Box1_Port1);
    }
  }
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

Now it works through the drain stage properly. Timer isn't working and not changing to the fill stage, or then back to normal.
Last edited by tyson_mitchell_88 on Mon Jan 18, 2016 12:23 pm, edited 1 time in total.
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

I thought the drain stage is working properly? Can you please accurately describe what is happening?
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

I have just done a re-test.

when I activate waterchange mode
>Box 1 port 7 & 8 stop
>box1 port 4 runs until ATOhigh is off
>stalls

It seems after the timed amount my DayLight leds flash. Ra stays like this, flashing the leds after the timed amount, until I reset it.

Sorry mate i'm getting up through the night to try get this nutted with the time difference. Thanks again for the help.
Last edited by tyson_mitchell_88 on Mon Jan 18, 2016 10:40 pm, edited 1 time in total.
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Ok got it. I'll take a look in a bit. Thanks for bearing with me. Not sure why the leds are flashing, sounds like your hitting a bus lock.
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

I had removed my expansiin hub because it was causing some problems. My lcd is shot so maybe it throwing something :(
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Ok, try this. I think this should be a bit simpler and do what you need. I also had it exit WaterChange Mode. You can remove the ButtonPress++; if you want to exit manually.

Code: Select all

static time_t wc_drain=0;
static time_t wc_refill=0;
  
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE || (hour()==18 && minute()==0 && second()==0)) {   // At 6pm every day the following to occur or when WC mode is activated
    wc_drain=now()+600; 
  }
  
  if (now() < wc_drain && ReefAngel.HighATO.IsActive()) {  // Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
    // box1 port 7 & 8 to turn off 
    ReefAngel.Relay.On(Box1_Port4);
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
  } else { 
    ReefAngel.Relay.Off(Box1_Port4);
    wc_drain=0;
    wc_refill=now()+600;
  }
  
    
  if (now() < wc_refill && !ReefAngel.HighATO.IsActive()) { // run box 1 port 1 until ato high is on for 10 mins (Salt In)
    // turn on box 1 port 7 & 8
    ReefAngel.Relay.On(Box1_Port1);
    ReefAngel.Relay.On(Box1_Port7);
    ReefAngel.Relay.On(Box1_Port8);
  } else { // return to usual
    ReefAngel.Relay.Off(Box1_Port1);
    wc_refill=0;
    ButtonPress++;
  }
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

Just uploaded, as soon as it was done port 7 & 8 kept switching on and off.

When I manually pushed the float switch to the off position Port 1 was activated and port 7 & 8 stayed off.
Image
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

I changed if (ReefAngel.DisplayedMenu=WATERCHANGE_MODE || (hour()==18 && minute()==0 && second()==0)) to only have = instead of ==.

Now once I upload (ATOHigh is on), ports 7 & 8 turn off and port 4 turns on.

When I manually change ATOHigh to off, ports 1, 7 & 8 turn on and port 4 turns off.

I need ports 7 & 8 to not toggle from the float switch. They are my tank returns, just need to turn off before wc drain and turn on before wc refill.
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Those should be == not =

I'll have to look more closely at what I'm doing. The switches could also be flipping if that's where they are set to. It's nice to deal with two switches instead of one. Have to figure out how to deal with that. Sorry this has been a pain.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Ok try this one. Last attempt tonight.

Code: Select all

  static time_t wc_drain=0;
  static time_t wc_refill=0;
  
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE || (hour()==18 && minute()==0 && second()==0)) {   // At 6pm every day the following to occur or when WC mode is activated
    wc_drain=now()+600; 
  }
  
  if (now() < wc_drain) {  // Activate box 1 port 4, until ato high is off, for 10 minutes (Sump out)
    // box1 port 7 & 8 to turn off 
    ReefAngel.Relay.On(Box1_Port4);
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
    if (!ReefAngel.HighATO.IsActive()) wc_drain=0;
  } else { 
    ReefAngel.Relay.Off(Box1_Port4);
    ReefAngel.Relay.On(Box1_Port7);
    ReefAngel.Relay.On(Box1_Port8);
    wc_refill=now()+600;
    wc_drain=0;
  }
      
  if (now() < wc_refill) { // run box 1 port 1 until ato high is on for 10 mins (Salt In)
    // turn on box 1 port 7 & 8
    ReefAngel.Relay.On(Box1_Port1);
    if (ReefAngel.HighATO.IsActive()) wc_refill=0;
  } else { // return to usual
    ReefAngel.Relay.Off(Box1_Port1);
    ButtonPress++;
    wc_refill=0;
  }
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

As soon as it uploaded port 1 turned on. 7 & 8 are on. Float switch changes nothing.

I appreciate this a lot mate. Sorry I'm not more of a help. Need to learn more.
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Roberto, or someone else, can you look at the code I've written. I'm not sure what I've done wrong :(
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

I have spread it out a bit to get my head around everything.

Now I am going through each bit at a time and testing. I have gotten this far.

Seems there is no actual 300 second delay between the modes.

Code: Select all

//Waterchange Mode    
    
  static time_t wc_drain=0;
  static time_t wc_tankoff=0;
  static time_t wc_tankup=0;
  static time_t wc_refill=0;
  
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE || (hour()==18 && minute()==0 && second()==0)) 
  {   // At 6pm every day the following to occur or when WC mode is activated
    wc_tankoff=now()+300; 
  }
  
  if (now() < wc_tankoff) 
  {  
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
    wc_drain=now()+300;
    wc_tankoff=0;
  }
  
  if (now() <wc_drain)
  {
    if (ReefAngel.HighATO.IsActive())
    ReefAngel.Relay.On(Box1_Port4);
    else  
    ReefAngel.Relay.Off(Box1_Port4);
    wc_tankup=now()+300;
    wc_drain=0;
  }
  
//  if(now() <wc_tankup)
//  {
//    ReefAngel.Relay.On(Box1_Port7);
//    ReefAngel.Relay.On(Box1_Port8);
//  } else {
//    wc_refill=now()+300;
//    wc_tankup=0;
//  }
  
//  if (now() < wc_refill)
//  {
//    ReefAngel.Relay.On(Box1_Port1);
//    if (ReefAngel.HighATO.IsActive()) wc_refill=0;
//  } else { 
//    ReefAngel.Relay.Off(Box1_Port1);
    //ButtonPress++;
//    wc_refill=0;
//  }
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Yeah to me you're check is instantly going to go to the next step because from the beginning wc_tankoff is 300 seconds into the future. You're check says if now() is less than the wc_tankoff value then wc_drain is now()+300 and wc_tankoff is 0 hmmm so wc_tankoff will always be > than now() so I don't see it going to the next step. Let me review what I posted....

Yes.. that looks like the issue. :) Let me try switching some logic around I think that may help. I'll use your variables

Try this:

Code: Select all

//Waterchange Mode    
    
  static time_t wc_drain=0;
  static time_t wc_tankoff=0;
  static time_t wc_tankup=0;
  static time_t wc_refill=0;
  
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE || (hour()==18 && minute()==0 && second()==0)) 
  {   // At 6pm every day the following to occur or when WC mode is activated
    wc_tankoff=now(); 
  }
  
  if (now()-wc_tankoff < 300) 
  {  
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
  } else {
    wc_drain=now();
    wc_tankoff=0;
  }
  
  if (now()-wc_drain < 300)
  {
    if (ReefAngel.HighATO.IsActive())
    ReefAngel.Relay.On(Box1_Port4);
    else  
    ReefAngel.Relay.Off(Box1_Port4);
  } else {
    wc_tankup=now();
    wc_drain=0;
  }
  
  if(now()-wc_tankup < 300)
  {
    ReefAngel.Relay.On(Box1_Port7);
    ReefAngel.Relay.On(Box1_Port8);
  } else {
    wc_refill=now();
    wc_tankup=0;
  }
  
 if (now()-wc_refill < 300)
  {
    ReefAngel.Relay.On(Box1_Port1);
    if (ReefAngel.HighATO.IsActive()) wc_refill=0;
  } else { 
    ReefAngel.Relay.Off(Box1_Port1);
    //ButtonPress++;
    wc_refill=0;
  }
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

So the correct logic is to subtract the time the trigger was made from the current time. If the diff is less than the time we want to run then we're good. Once the clock goes past 300 seconds into the future, the time recorded for the trigger will always be better than the runtime. Reverting it to 0 is redundant but good to make it clear. I think this will work now :) Good Luck
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: water change build

Post by lnevo »

Here's an example from my INO with working code. When we trigger the Swabbie to run, it runs for two minutes, otherwise we treat it like a dosing pump and run it 4 times a day for 2 minutes

Code: Select all

  static time_t t;
  
  // Manual mode
  if (ReefAngel.Relay.isMaskOn(Swabbie)) {
    ReefAngel.Relay.Auto(Swabbie);
    t=now();
  }  

  if (now()-t < runtime) {
    ReefAngel.Relay.On(Swabbie);
  } else {
    ReefAngel.DosingPumpRepeat(Swabbie,0,repeat,runtime);    
  }  
Now that you helped me see what I was doing wrong, it all makes sense now :)
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

lnevo wrote:Here's an example from my INO with working code. When we trigger the Swabbie to run, it runs for two minutes, otherwise we treat it like a dosing pump and run it 4 times a day for 2 minutes

Code: Select all

  static time_t t;
  
  // Manual mode
  if (ReefAngel.Relay.isMaskOn(Swabbie)) {
    ReefAngel.Relay.Auto(Swabbie);
    t=now();
  }  

  if (now()-t < runtime) {
    ReefAngel.Relay.On(Swabbie);
  } else {
    ReefAngel.DosingPumpRepeat(Swabbie,0,repeat,runtime);    
  }  
Now that you helped me see what I was doing wrong, it all makes sense now :)

So MaskOn is seeing when you manually change the port?
Image
tyson_mitchell_88
Posts: 80
Joined: Thu Nov 05, 2015 2:45 pm
Location: Australia

Re: water change build

Post by tyson_mitchell_88 »

When I upload it is triggering everything. Will go through some troubleshooting again.

lnevo wrote:Yeah to me you're check is instantly going to go to the next step because from the beginning wc_tankoff is 300 seconds into the future. You're check says if now() is less than the wc_tankoff value then wc_drain is now()+300 and wc_tankoff is 0 hmmm so wc_tankoff will always be > than now() so I don't see it going to the next step. Let me review what I posted....

Yes.. that looks like the issue. :) Let me try switching some logic around I think that may help. I'll use your variables

Try this:

Code: Select all

//Waterchange Mode    
    
  static time_t wc_drain=0;
  static time_t wc_tankoff=0;
  static time_t wc_tankup=0;
  static time_t wc_refill=0;
  
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE || (hour()==18 && minute()==0 && second()==0)) 
  {   // At 6pm every day the following to occur or when WC mode is activated
    wc_tankoff=now(); 
  }
  
  if (now()-wc_tankoff < 300) 
  {  
    ReefAngel.Relay.Off(Box1_Port7);
    ReefAngel.Relay.Off(Box1_Port8);
  } else {
    wc_drain=now();
    wc_tankoff=0;
  }
  
  if (now()-wc_drain < 300)
  {
    if (ReefAngel.HighATO.IsActive())
    ReefAngel.Relay.On(Box1_Port4);
    else  
    ReefAngel.Relay.Off(Box1_Port4);
  } else {
    wc_tankup=now();
    wc_drain=0;
  }
  
  if(now()-wc_tankup < 300)
  {
    ReefAngel.Relay.On(Box1_Port7);
    ReefAngel.Relay.On(Box1_Port8);
  } else {
    wc_refill=now();
    wc_tankup=0;
  }
  
 if (now()-wc_refill < 300)
  {
    ReefAngel.Relay.On(Box1_Port1);
    if (ReefAngel.HighATO.IsActive()) wc_refill=0;
  } else { 
    ReefAngel.Relay.Off(Box1_Port1);
    //ButtonPress++;
    wc_refill=0;
  }
Image
Post Reply