Page 7 of 9

Re: Lee's Feature Complete PDE

Posted: Mon Mar 02, 2015 8:57 pm
by alexwbush
Can you explain your memory use? How do you modify your memory? I assume you can from the RA memory in the app? Are they custom locations?

Re: Lee's Feature Complete PDE

Posted: Tue Mar 03, 2015 6:02 am
by lnevo
Yes. Custom locations. I use the direct http calls to modify them or a web page form I have created. The RA app does not currently have a way to change custom memory locations. I believe the android one does. I try to use memory rather than hardcoding so I can modify everything on the fly without recompiling. I've gone about a year or so without any major modifications thanks to this.

Re: Lee's Feature Complete PDE

Posted: Mon Jun 22, 2015 9:37 pm
by MDB1029
I didn't see it listed here so i thought i would ask, do you run any cloud and lightning code along with your sun location code? I am hoping to be able to incorporate both.

Re: Lee's Feature Complete PDE

Posted: Tue Jun 23, 2015 7:55 am
by lnevo
Not yet. The SunLocation is used to get the date/time for your main LED schedule. I haven't looked closely at the cloud/lightnign code yet, but I believe you still need to set manually your lighting schedule. The SunLocation class will set the schedule in Memory if you're using Internal Memory today.

Re: Lee's Feature Complete PDE

Posted: Mon Jul 13, 2015 1:03 pm
by lnevo
Roberto,

I can no longer post my code. It's > 60,000 characters. I'm at 69k :)

Re: Lee's Feature Complete PDE

Posted: Mon Jul 13, 2015 1:18 pm
by Sacohen
You broke the forum.

Re: Lee's Feature Complete PDE

Posted: Mon Jul 13, 2015 1:34 pm
by lnevo
67504 characters, 5338 words, 1915 lines of code.

Re: Lee's Feature Complete PDE

Posted: Mon Jul 13, 2015 3:33 pm
by rimai
:lol:

Re: Lee's Feature Complete PDE

Posted: Mon Jul 13, 2015 3:35 pm
by 89delta
MDB1029 wrote:I didn't see it listed here so i thought i would ask, do you run any cloud and lightning code along with your sun location code? I am hoping to be able to incorporate both.
I use the sunclass in my code as well as cloud and lighting....not sure of the link but check out my code.

Sent from my Samsung Galaxy Note 3

Re: Lee's Feature Complete PDE

Posted: Mon Jul 13, 2015 3:58 pm
by lnevo
Yes of course :)

Re: Lee's Feature Complete PDE

Posted: Tue Jul 28, 2015 6:01 pm
by 89delta
Lnevo,

How would I go about using your gap fill-in code for moonlights with my LEDs on the Daylight and actinic PWM outputs? My ver 2.1 code can be found on bottom of page....thanks for looking.

http://forum.reefangel.com/viewtopic.php?f=11&t=4731

Re: Lee's Feature Complete PDE

Posted: Wed Aug 05, 2015 5:16 am
by lnevo
What ports are your moonlights on?

Re: Lee's Feature Complete PDE

Posted: Wed Aug 05, 2015 5:22 am
by 89delta
I don't have them on ports. I use the moonphase coding on my actinic pwm channel.

Sent from my Samsung Galaxy Note 3

Re: Lee's Feature Complete PDE

Posted: Thu Aug 06, 2015 8:58 pm
by lnevo
I'm not sure I'm following.

My LEDs don't go below a certain effective %. After around 7% any lower there is no change in PAR or brightness and it is still pretty bright. I have my moonlights come on at 100% and ramp down to 0% to make up for that. I turn the moonlights on right before my main lights go off.

Since your moonlights are on the same channel as your LED there's nothing that can be "filled in"

Re: Lee's Feature Complete PDE

Posted: Fri Aug 21, 2015 6:11 am
by lnevo
Roberto, were you able to up the character count at all? Is it possible?

Re: Lee's Feature Complete PDE

Posted: Fri Aug 21, 2015 9:08 am
by rimai
Which count?

Re: Lee's Feature Complete PDE

Posted: Fri Aug 21, 2015 11:54 am
by lnevo
lnevo wrote:Roberto,

I can no longer post my code. It's > 60,000 characters. I'm at 69k :)

Re: Lee's Feature Complete PDE

Posted: Fri Aug 21, 2015 11:56 am
by rimai
Ahhh.
Try again. Increased to 100K
If it doesn't work, I may need to reboot the forum app.

Re: Lee's Feature Complete PDE

Posted: Fri Aug 21, 2015 1:19 pm
by lnevo
Cool. I'll give it a try shortly.

Re: Lee's Feature Complete PDE

Posted: Fri Aug 21, 2015 2:23 pm
by lnevo
Ok the code is now up to date. It worked :) A few bug fixes since July, especially on the third dosing pump.

Re: Lee's Feature Complete PDE

Posted: Fri Aug 28, 2015 11:57 pm
by ritz
Where did you post the code? The only one I could find was from 2013. I've been dying to steal some of your coding! ;)

Thanks.

Lee's Feature Complete PDE

Posted: Sat Aug 29, 2015 4:08 am
by lnevo
Its in the 2nd post. It may say its from 2013 but I edit it. It may say the time I edited in small print

Re: Lee's Feature Complete PDE

Posted: Wed Feb 10, 2016 7:39 pm
by lnevo
Auto Water Change and Revamped mixing station.

ImageImage

Re: Lee's Feature Complete PDE

Posted: Wed Feb 10, 2016 7:40 pm
by lnevo
Tanks looking good tonight

ImageImageImage

Re: Lee's Feature Complete PDE

Posted: Tue Mar 15, 2016 5:09 am
by MDB1029
I am having trouble finding all the code needed for your coral acclimation mode. Can you advise on how to implement this?

Re: Lee's Feature Complete PDE

Posted: Tue Mar 15, 2016 5:15 am
by lnevo
Which part do you want? The photoperiod or the dimming or both? Are you using SunLocation? Can you point me to your current code?

Re: Lee's Feature Complete PDE

Posted: Tue Mar 15, 2016 5:36 am
by MDB1029
both photoperiod and dimming if possible. I don't use the sun location at this time because i have just never implemented it.

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>

    ////// Place global variable code below here
        int DaylightPWMValue=0;        // For cloud code


    ////// 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 = Port1Bit | Port4Bit;
        // Ports toggled in Water Change Mode
        ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit;
        // Ports toggled when Lights On / Off menu entry selected
        ReefAngel.LightsOnPorts = 0;
        // Ports turned off when Overheat temperature exceeded
        ReefAngel.OverheatShutoffPorts = Port2Bit | Port3Bit;
        // 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 );   //return pump
        ReefAngel.Relay.On( Port4 );   //skimmer
        
        ////// Place additional initialization code below here
       

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

    void loop()
    {
        ReefAngel.StandardHeater( Port2 );  //heater 1
    if ( ReefAngel.Params.Temp[T1_PROBE] < (InternalMemory.HeaterTempOn_read() - 10)) { ReefAngel.Relay.On(Port3); };  //heater 2 on
    if ( ReefAngel.Params.Temp[T1_PROBE] > (InternalMemory.HeaterTempOff_read() - 5)) { ReefAngel.Relay.Off(Port3); };  //heater 2 off
        ReefAngel.SingleATOLow( Port5 );  //ATO pump
            DaylightPWMValue=PWMSlopeHighRes(10,00,20,0,0,55,60,0);  //daylights 
         CheckCloud();
         ReefAngel.PWM.SetChannelRaw(1,DaylightPWMValue);
        ReefAngel.PWM.SetChannelRaw(0,PWMSlopeHighRes(9,00,21,00,0,50,90,0));  // Blues
        ReefAngel.PWM.SetChannelRaw(2,PWMSlopeHighRes(9,30,20,30,0,55,60,0));  // spectrum
        ReefAngel.StandardLights(Port6,18,0,10,0);  // Fuge light from 1800 to 1000
        if ( ReefAngel.PWM.GetChannelValueRaw(0) < 16 ||ReefAngel.PWM.GetChannelValue(0)>100)
            ReefAngel.PWM.SetChannelRaw(0,16) ;  //moonlight value
        ReefAngel.DosingPumpRepeat1( Port7 );  //ALK doser
        ReefAngel.DosingPumpRepeat2( Port8 );  //Cal doser
       
        ////// Place your custom code below here
       

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

        // This should always be the last line
        ReefAngel.Portal( "MDB1029" );
        ReefAngel.DDNS( "Reef" ); // Your DDNS is MDB1029-Reef.myreefangel.com
        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 33

          // 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 14

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

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

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

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

          // 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 50

          // 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 result 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:  { Calm, 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[] = {Mega,Calm,Fast};

          // 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/40.95,0,180)*40.95;
              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=4095;
                  }
                  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()
        {
          int a=random(1,5);    // Pick a number of consecutive flashes from 1 to 4.
          for (int i=0; i<a; i++)
          {
            // Flash on
            int newdata=4095;
            Wire.beginTransmission(0x40);      // Address of the dimming expansion module
            Wire.write(0x8+(4*1));             // 0x8 is channel 0, 0x12 is channel 1, etc.  I'm using channel 1.
            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.
            newdata=ReefAngel.PWM.GetChannelValueRaw(1);   // 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;
        }


Re: Lee's Feature Complete PDE

Posted: Tue Mar 15, 2016 4:05 pm
by MDB1029
Sorry, I have another question for you as well.

I would really like to add the moon phases. My current moonlights run off my regular dimming channel 0 which is my main Actinic/Royal Blue channel with this code,

Code: Select all

if ( ReefAngel.PWM.GetChannelValueRaw(0) < 16 ||ReefAngel.PWM.GetChannelValue(0)>100)
            ReefAngel.PWM.SetChannelRaw(0,16) ;  //moonlight value
Would i be able to implement the moon phases off of this same channel?

Re: Lee's Feature Complete PDE

Posted: Wed Mar 16, 2016 7:46 pm
by MDB1029
lnevo wrote:Which part do you want? The photoperiod or the dimming or both? Are you using SunLocation? Can you point me to your current code?
I have my code posted here now http://forum.reefangel.com/viewtopic.php?f=11&t=5934

Re: Lee's Feature Complete PDE

Posted: Wed Mar 16, 2016 8:18 pm
by lnevo
Ok give me a little time and try to parse through your code and then see what we can do.