Weather Simulation for Dimming expansion module

Share you PDE file with our community
rufessor
Posts: 293
Joined: Tue Oct 25, 2011 7:39 am

Re: Weather Simulation for Dimming expansion module

Post by rufessor »

Based upon what Roberto just said-

Porting to the head unit is not probably overly difficult. The code has no special "code" that would only work on the Dimming module, it is however relatively large and would be unlikely to fit on anything other than the RA+. I had spent a little time trying to create an object library that would bring this code into the distribution. I admit to being slightly over matched in my coding skills as I have no OO C++ experience and limited OO Perl experience... so I got it split into what seemed to be rational segments, and then decided I was unsure what/how exactly to take this split up code and do something with it so that it could get packaged into the libraries.

At this point, given my availability and ability I would be happy to work with a more experienced person to see this through but am uncertain I can do this on my own without dedicating way too much time to a C++ learning curve when the only place I use this language is for RA.

If someone is willing to help (and I honestly do not think its going to take much) finish this, we should talk.

If this occurs, it will simply be part of the distribution and could be enabled by adding a few lines of code and includes.
rufessor
Posts: 293
Joined: Tue Oct 25, 2011 7:39 am

Re: Weather Simulation for Dimming expansion module

Post by rufessor »

Lnevo? Any time or interest?
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Weather Simulation for Dimming expansion module

Post by dlplunkett44 »

Ok, so I'm trying to port this into my code, and when compiling, its giving me this error:

Globals\Globals.cpp.o: In function `MoonPhase()':
C:\Users\DaveElise\Documents\Arduino\libraries\Globals/Globals.cpp:116: multiple definition of `MoonPhase()'
Small_Reef.cpp.o:C:\Users\DAVEEL~1\AppData\Local\Temp\build4725006818650472374.tmp/Small_Reef.cpp:746: first defined here

Here is my code:

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>
#include <avr/wdt.h>
//includes for SWFLTEK functions
#include <stdlib.h>
#include <math.h>

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

//***********************************ARRAYS YOU MUST MODIFY TO MAKE YOUR TANK SET UP WORK*****************************
//YOU MUST READ EVERY WORD IN THIS SECTION IN ORDER TO APPROPRIATELY CONFIGURE THIS PROGERAM- READ EVERY LINE BELOW///
byte ChMax[]={200,220,200,220,225,0,0,0};//Incremental value (Max-flicker) above flicker you want as max intensity (!!!!!!! Light Set Point is ChMax PLUS Flicker !!!!!!) 
byte flicker[]={31,31,31,31,40,0,0,0};//need to input actual values here for flicker point on all channels in PWM expansion box
boolean Wchannel[]={1,0,1,0,0,0,0,0}; //use 1 to designate white channel (i.e. off during storm and used for lightning).  Array corresponds to PWM channel 0-5 in order
//Array to give direction to dimming.  e.g. DimOrder[]={0,0,1,1,0,0} (cloud chase effects, just group channels you want to dim together during a cloud or storm 
//as either a 0 or a 1, i.e. all left side channels are 0 all right are 1 or all front are 0 all back are 1 or whatever
//(which is zero or 1 will change who dims first).  set them all to 0 if your tank has no left/right or front/back lights.
byte DimOrder[]={0,0,1,1,1,0,0,0};
//set all channel positions that you would like to use for the lightning strike effect to 1 (0-5 are PWM channels 6,7 are Main PWM outs)- and channels with a 0 are not used in strike
byte StrikeChannel[]={1,1,1,1,1,0,0,0};
byte MoonCh[]={0,0,0,0,1,0,0,0};//place a 1 in the array position of all lighting channels you would like to use a moon lighting (this does not preclude their use in other phases (day, storm etc)
//**********************************DONE CHANGING THINGS HERE BUT YOU MUST CHANGE ChOffset array IN CalcSUN function******


//defines for SWFLTEK functions
// arc-seconds per radian
#define _sec_rad 206264.806247096370813

// axial tilt of earth at epoch, in radians
#define _tilt 0.409092804222329

// tropical year in seconds... rounding error accumulates to 26 seconds by the year 2136
#define _tropical_year 31556925

// 'zenith' of rising (setting) sun in radians (360 - 2 * 90.833 degrees)
#define _zenith 3.11250383272322

//*******************GLOBAL VARIABLE DECLERATIONS FOR MHOCKIN Weather package*************************************
//Unless your planning on editing the program DO NOT CHANGE ANYTHING HERE
long latitude, longitude;
byte TrueIntensity[8];//array used to place hold final write values for PWM intensity setting
long elapsedTime;//used multiple places as elapsed since midnight
long newDay;
unsigned long rise;//time in seconds from the year 2000 (GMT) for sunrise
unsigned long set;//time in seconds from the year 2000 (GMT) for sunrise
long ChRiseSet[16];//times of rise and set for all 8 channels based upon offsets from calc rise and set values
float ChSlope[16];//slopes for 1/2 day calculations based upon time from offset to midday for channel 1-8
long CloudMaster[20];// Set up array to hold start and end times for clouds for the day-
long midDay;// exactly 1/2 way between rise and set, i.e. solar noon for latitudes <60 close enough for us... 
byte PWMports[] ={
    3,5,6,9,10,11};
byte ChannelValue[8];// Array to store output of insolaiton which may be modified and stored in TrueIntensity which is used to write to the PWM channels
unsigned long StrikeStart;//timer to keep track of strike sequence
int StrikeMaster[20];//Array to hold random strike pattern generated by weather array is sized to MAX needed given strike patter generator (8 strikes=16 positions)
byte StrikeNumber;//place to hold total number of strikes this sequence
boolean StrikeNow;//starts lightning strike sequence in loop state change made in weather/storm loop
byte StrikeCount;//Used to properly sequence strike sequence for delay between strikes
byte cmdnum=255;
byte datanum=255;
byte dow=0;//day of week
byte strikePattern, strikeTime;//used in Lightning() for timing of particular instance of strike 
boolean Cloud;// are we in a cloud interval on days that have clouds
boolean CloudToday;//set in CalcSun if randomization yields a day with clouds.
boolean IsStorm;// are we in a storm
byte CloudsTotal;// how many clouds today
long lastmillis;// variable to track millis to enable cloud and insolation loop restriction by time
boolean StormAdvance;//storm timer for light effect advance
boolean InsolationAdvance;//when true we recalculate light intensity during clear sky (every 3 seconds seems more than often enough)
byte counter;//used to track millis advance for insolation,cloud trigger
//****************************************
//END HEADER/Global Variable declaration//
//*****

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


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


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


    ////// Place additional initialization code below here
    
    
   Serial.begin(57600);
    Wire.begin(8);
    //Wire.onReceive(receiveEvent);
    //Wire.onRequest(requestEvent);

    pinMode(3,OUTPUT);
    pinMode(5,OUTPUT);
    pinMode(6,OUTPUT);
    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
    wdt_enable(WDTO_1S);
    unsigned long seed=0, count=32;
    while (--count){
      seed = (seed<<1) | (analogRead(5)&1);
    }
      randomSeed(seed);//start random generator at a different point each time (not perfect but whatever its gonna be pretty damn random)
    setSyncProvider(RTC.get);   // the function to get the time from the RTC
    setSyncInterval(SECS_PER_HOUR);  // Changed to sync every hour.
    
    dow=0;//set Day Of Week (dow) to a 0 value which is impossible (day()=1-7)... so we trigger calcSun on restart 
    StrikeNow=false;//no lightning strike yet
    CloudToday=false;//set to no clouds so CalcSun can set correctly if should be true
    Cloud=false;//set cloud to false
    IsStorm=false;//set storm to false
    lastmillis=millis();//start our millis timer now
    counter=0;//used in weather for triggering a storm, triggering lightning in a storm.
    StrikeCount=0;//Number of lightning strikes in the sequence.. set to zero until initialized in sequence
 


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


//Standard PWM Functions Receive/Process
void receiveEvent(int howMany) {
    wdt_reset();
    if (howMany==5){
        byte cmd1, cmd2, cmd3, cmd4, cmd5;
        cmd1=Wire.read();
        cmd2=Wire.read();
        cmd3=Wire.read();
        cmd4=Wire.read();
        cmd5=Wire.read();
        if (cmd1=='$' && cmd2=='$' && cmd3=='$'){
            cmdnum=cmd4;
            datanum=cmd5;
            //Serial.println(cmd4,DEC);
            //Serial.println(cmd5,DEC);
        }
    }
    else{
        for (int a=0;a<howMany;a++){
            Wire.read();
        }
    }  
}

void ProcessCMD(byte cmd, byte data){
    wdt_reset(); 
}

//End Standard Functions
//*********************************************************************************************************************************
//Start of sunrise, sunset and cloud calculations- runs on reset and once a day thereafter.
void CalSun(){
   //Serial.println("CalSun Run Now");

        //*********************YOU NEED TO CHANGE THESE VALUES Read instructions in their ENTIRETY and CAREFULLY change to values for your tank and geographical region***************************
        //channels 0-5 are PWM expansion board lights 6,7 are ReefAngel Controller PWM outputs
        //offsets for rise/set all values in seconds offset from calculated rise or set value (-) am offset=longer day****** (-)pm offset=shorter day)
        //array order is ch0 am offset, pm offset, ch1 am offset, pm offset etc..
        //THESE values are the number of seconds that a particular channel will be offset from the rise/set time, i.e. negative to rise earlier/set earlier
        int Choffset[]={
            -600,0,-1800,6000,0,600,-1200,6600,-2200,6600,0,0,0,0,0,0};
        // NOW SET YOUR LATIDTUDE AND LONGITUDE COORDINATES as Degrees, Minutes, Seconds of Lat and Lon
        //If Your NORTH of the equator your LONGITUDE must START with a NEGATIVE number (the rest are positive) e.g. All of North America, Europe, Russia etc are negative
        //If Your EAST of the Prime Meridian your LATITUDE must START with a NEGATIVE number (the rest are positive), e.g. Most of Europe, All of China, India, Austraila, Russia etc are negative
       latitude=dmsToSeconds(40,44,00);//United States of America- Salt Lake City, local time is -7 hours GMT 
       longitude=dmsToSeconds(-111,47,00);
        //**********************ok now were done changing things IF YOU CHANGED the Top part of the GLOBAL variable decleration AND this... your FULLY configured and ready to load******************************************** 
   
    if (dow==0){//if the controller has resarted we need to find midnight
      long hours, minutes;//store current elapsed local hours as total seconds from midnight
      time_t t=now();//store current clock time to parse
      hours=hour(t);
      hours=(hours*3600);//current hour number 0-23 as seconds
      minutes=minute(t);
      minutes=(minutes*60);//minutes of current hour as seconds
      newDay=now();
      newDay-=(hours+minutes);//Convert current local unix epoch time to local unix epoch time of midnight
    }
    else if (dow!=0){//if we did not restart but the day is new then it is midnight and were good to go..
      newDay=now();
    }
      
    //#define SECS_YR_2000 (946684800) the time at the start of y2k (need to subtract from unix epoch time to bring to Y2K origin
    newDay-=946684800;//convert GMT unix Epoch to seconds elasped since 2000 for GMT midnight of today
    
    rise=newDay;//set value to send to SunRise as midnight GMT in seconds from Y2K
    set=newDay;//
    //Calculate rise time and set time using Epherma Library functions (see end of code) 
    SunRise(&rise);//call to Epherma function
    SunSet(&set);//Call to Epherma functionunsigned long newDay;
  
   /*Serial.print("rise and set=  ");
   Serial.println(rise);
   Serial.println(set);
   Serial.print("newDay as seconds since 2000 to todays midnight=  ");
   Serial.println(newDay);*/
    rise=(rise-newDay);// set to elapsed seconds of day
    set=(set-newDay);
   /*Serial.print("rise and set as elapsed seconds of day=  ");
   Serial.println(rise);
   Serial.println(set);*/
    newDay+=946684800;//Convert newDay back to unix epoch GMT midnight today (used in loop to determine how far we are into the day) 
   /*Serial.print("newDay as seconds since since 1970 to todays midnight=  ");
   Serial.println(newDay);
   Serial.print("elapsed is");
   long elapsed=now()-newDay;
   Serial.println(elapsed);*/
   
        //Calculate rise and set times for all channels in equivlants to elapsed seconds from midnight today
        //populate array for chRise and Set as well as chSlope for 0.5pi/ half day lenght for each channel from midday (asymmetric days are allowed)
        float deltaY=1.570796327;//1/2 * pi as integer by scaling* 10^9 to fill UL
        midDay=(((set-rise)/2)+rise);
        long HalfDayLength=((set-rise)/2);
       
        for (byte b=0;b<16;b++){//working as of April 5 2012 serial tested
            if (b%2==0){
                ChRiseSet[b]=rise+(Choffset[b]);
                ChSlope[b]=(deltaY/(float)(HalfDayLength-(Choffset[b])));
            }
            else if (b%2==1){
                ChRiseSet[b]=set+(Choffset[b]);
                ChSlope[b]=(deltaY/(float)(HalfDayLength+(Choffset[b])));
            }
        }  
        
        //***************** to CHANGE THE chance of Clouds actually occuring on a given day************************
        byte CloudChance=100;//% Chance of a Cloud every day
        //****************************now were done- did you use a value from 0-100 without a decimal?****************
        
  
        byte RainMaker=random(1,101); 
        if (RainMaker<=CloudChance){
            CloudToday=true;//used to trigger weather function, can also be used to send flag to controller
        }
        else if (RainMaker>CloudChance){
            CloudToday=false;//see above comment on CloudToday
            return;
        }
        long dayLength=0;
        for (byte a=1;a<16;a=(a+2)){//determine maximum day length given light on tank that is not moon light, this will yield night clouds and storms (and a storm after dark is severe... always
          if (a==0){
            if (((set+Choffset[a])-rise)>(set-rise)){
              dayLength=((set+Choffset[a])-rise);  
            }
            else dayLength=(set-rise);
          }
          else if (a!=0){
            if (dayLength<((set+Choffset[a])-rise)){
              dayLength=((set+Choffset[a])-rise);
            }
          }
        }
        
        // number of clouds possible for the day, max and min
        byte CloudsMax=10;//DONT INCREASE BEYOND 10 or it will DIE, or increase array size to handle it (among other things)
        byte CloudsMin=4;//use 2 as a minimum
        CloudsTotal=random(CloudsMin,(CloudsMax+1));
        
        // Average day is 50,000 secs so if 4 clouds and 10% that gets you 5,000 seconds of clouds (about 1800 seconds length for each of the 4 clouds in independent segments (if 4 is # clouds)
        byte OvercastMin=((CloudsTotal*10)/5);//Min cloud length will be about 1000 seconds (15 mins)- 1 hour min of clouds if you have 4, 2 hours if you have 8
        byte OvercastMax=((CloudsTotal*10)/2);//max cloud length will be about 2500 seconds (45 mins)- 6 hours max of clouds if you have 8, 3 hours max if you have 4
        float Overcast=random(OvercastMin,OvercastMax);
        Overcast=(Overcast/100);
        
        // split the total lenght of time for clouds into equal segments and then to randomly chop or add time to the 
        //segments such that cloud length is variable.  Then distribute into random parts of the day and fill array with start,duration pairs for clouds
        int CloudLength;
        CloudLength=((dayLength*Overcast)/CloudsTotal);//average cloud length
        long SunSegment=((dayLength-(dayLength*Overcast))/(CloudsTotal+1));//average sun length between clouds
        float CloudFraction=0;
        float SunFraction=0;
       
        //start by zero filling CloudMaster array
        for (byte a=0; a<20; a++){
          CloudMaster[a]=0;
        }
        
        byte b=0;//used to get pairs of fraction for SunFraction in for loop
        byte c=0;//used to get pairs of fraction for CloudFraction in for loop
        //now randomize cloud length and sunsegment length as pairs to get different looking days- 
        for (byte a=0; a<(CloudsTotal*2); a++){
          if (a%2==0){
            if (b==0){
              if (a==0){
                SunFraction=random(20,181);//vary each pair of SunSegments from 20%-180% of possible length such that every pair =2*SunSegment in length
                SunFraction=(SunFraction/100);
                CloudMaster[a]=(SunFraction*SunSegment);
              }
              else if (a<((CloudsTotal*2)-2)){
                SunFraction=random(20,181);//vary each pair of SunSegments from 20%-180% of possible length such that every pair =2*SunSegment in length
                SunFraction=(SunFraction/100);
                CloudMaster[a]=(SunFraction*SunSegment);
                b++;
              }
              else if (a==((CloudsTotal*2)-2)){
                SunFraction=(2-((float)CloudMaster[0]/(float)SunSegment));
                CloudMaster[a]=(SunFraction*SunSegment);
              }
                
            }
            else if (b==1){
              if (a<((CloudsTotal*2)-2)){
                SunFraction=(2-SunFraction);//were on the second part of a pair
                CloudMaster[a]=(SunFraction*SunSegment);
                b=0;//reset so next time we start a new fraction
              }
              else if (a==((CloudsTotal*2)-2)){
                SunFraction=(2-((float)CloudMaster[0]/(float)SunSegment));
                CloudMaster[a]=(SunFraction*SunSegment); 
              }
            }
          }
          else if (a%2==1){//if were in odd positions we need to determine cloud lengths in random pairs such that each pair =2*CloudLength in length
            if (c==0){
              CloudFraction=random(20,181);//vary each pair of SunSegments from 20%-180% of possible length such that every pair =2*SunSegment in length
              CloudFraction=(CloudFraction/100);
              CloudMaster[a]=(CloudFraction*CloudLength);
              c++;       
            }
            else if (c==1){
              CloudFraction=(2-CloudFraction);
              CloudMaster[a]=(CloudFraction*CloudLength);
              c=0;//reset so next loop finds a new fraction
            }
         }
      }
        /*Serial.println("here is cloud master in is entirety prior to forming start and end pairs");
        for (byte a=0;a<20;a++){
          Serial.println(CloudMaster[a]);
        }*/
      //reframe array to generate cloud start, cloud end, cloud start, cloud end
      for (byte a=0; a<(CloudsTotal*2); a++){
        if (a==0){// if were starting our first cloud we need to add to rise value to first sun segment
          CloudMaster[a]=rise+CloudMaster[a];
        }
        else {
          CloudMaster[a]=(CloudMaster[a-1]+CloudMaster[a]);//just add prior values together e.g. (second position is cloud end so to find end add rise corrected start time with duration)
                                                           // subsequent start would be end of 1st cloud + next sunsegment fraction
        }
      }
        /*Serial.println("here is cloud master in is entirety as start and end pairs");
        for (byte a=0;a<20;a++){
          if (a%2==0){
            Serial.print("Start time=");
            Serial.println(CloudMaster[a]);
          }
          else {
            Serial.print("End time=");
            Serial.println(CloudMaster[a]);
          }
        }*/
}//END SunCalc FUNCTION

void Insolation()
{
  InsolationAdvance=false;//reset this flag now that we have entered function

        //define Pi as delta Y for slope since cos 0.5-1.5 Pi goes 0-1-0 in 0.5 pI increments slope of 1/2 day (0-1 intensity) delta Y is 1/2 Pi 
        float Pi=3.1415926;//scale to 10^8
        float PiHalf=1.5707963;//scale to 10^8
        
        float secSoFar;//variable to account for seconds elapsed for each channel 1/2 day period from rise-->midDay and midDay-->set
        
        /* using -cos(pi/2+elapsedTime/slope) calculate fractional intensity of each channel throughout the day
         use flicker points to adjust minimum intensity to stable light.  Turn off lights after set or before rise etc.
         by splitting into half days centered on midday (1/2 ofset-rise) we center exactly the cos function for every channel so color blends are maintained 
         throughout intensity ramp... more or less ... change intensity every 120 seconds throughout the day*/
         if (elapsedTime<=midDay){
           byte c=0;//loop counter
            for (byte b=0;b<16;b=(b+2)){
                if (elapsedTime>=ChRiseSet[b]){
                    secSoFar=(elapsedTime-ChRiseSet[b]);//just account for length of every channel 1/2 day and switch at midDay
                    ChannelValue[c]=flicker[c]+ChMax[c]*(-cos(PiHalf+(ChSlope[b]*secSoFar)));
                 }
                 else if (elapsedTime<ChRiseSet[b]){
                   if (MoonCh[c]==1){  
                      byte MoonToday=MoonPhase()*0.5;//SCALE FACTOR to DIM moon setting for use with HIGH power LED as moon light
                      if (MoonToday==0) ChannelValue[c]=0;
                      else if (MoonToday<flicker[c]) ChannelValue[c]=flicker[c];
                      else ChannelValue[c]=MoonToday;
                   }
                   else if (MoonCh[c]==0){
                     ChannelValue[c]=0;//its dark and this is not a moon phase channel
                   }
                 }
              c++;//index by one so we count 0-7 as b goes 0-14 by twos
            }
        }  
        else if (elapsedTime>midDay){
            byte c=0;//loop counter
            for (byte b=1;b<16;b=b+2){
              if (elapsedTime<=ChRiseSet[b]){
                    secSoFar=(elapsedTime-midDay);
                    ChannelValue[c]=flicker[c]+ChMax[c]*(-cos(Pi+(ChSlope[b]*secSoFar)));          
               }
               else if (elapsedTime>ChRiseSet[b]){
                   if (MoonCh[c]==1){  
                      byte MoonToday=MoonPhase()*0.5;//SCALE FACTOR to DIM moon setting for use with HIGH power LED as moon light
                      if (MoonToday==0) ChannelValue[c]=0;
                      else if (MoonToday<flicker[c]) ChannelValue[c]=flicker[c];
                      else ChannelValue[c]=MoonToday;
                   }
                   else if (MoonCh[c]==0){
                     ChannelValue[c]=0;//its dark and this is not a moon phase channel
                   }
                }
              c++;//index to count 0-7 as b counts 1-15 by twos.
            }
        }   
}//END function
//WEATHER FUNCTION BEGIN
void Weather ()  
{
    static byte loopCount;
    static float CloudCover; // variable to store value in random walk - declared static to accumulate Cloud effect
    static float PriorCloudCover;  //used to "delay" one side of the tank from the other in cloud passing effects
    static long StormStart;
    static long StormEnd;
    static long CloudEnd;
    static boolean wtrigger;//use to track the first run of functions to calculate random times that become fixed, see change from cloud to storm for useage
    static byte Counter;//used to trigger storms from cloud you can change its if loop comparison to decrease or increase storm rate see below in cloud==true if loop
    static byte Severity;
    static byte StormCount;// used to limit X storms per cloud and to choose which cloud can have a storm
    static int StepSize;
    static int LastStepSize;
    //check to see if were having a scheduled cloud
    if (Cloud==false){
      //Write Insolation values to TrueIntensity so the loop will pick them up and the cloud/storm will get the right data (since intensity changes during the day)
      for (byte a=0; a<8; a++){//this must be above the next loop
            TrueIntensity[a]=ChannelValue[a];//this is where intensity is set for the PWM channel analog write in the loop... don't mess with this.
        }   
      for (byte a=0; a<(CloudsTotal*2); a=(a+2)){//if its time for a cloud, run it
         if ((elapsedTime>=CloudMaster[a]) && (elapsedTime<=CloudMaster[(a+1)])) {
             CloudEnd=CloudMaster[(a+1)];//to avoid this loop running true during the compute cycles at the end of the cloud and before elapsedTime advances a second, actual cloud does not
             //Serial.print("We started a cloud and its end is=");
             //Serial.println(CloudEnd);
             CloudCover=CloudStart(CloudMaster[a]);//CloudStart modifies TrueIntensity to get us to 50% intensity at the start of the cloud effect and also sets cloud=true to bypass this
             Counter=0;
             StormCount=random(0,3);//the number of storms MAX that may occur in this cloud (remember Random is range= -1 on high end)
             loopCount=1;
             LastStepSize=0;//zero out cloud random walk variables
             StepSize=0;//zero out cloud ranodm walk variables
             return;//exit having started a cloud in CLoudStart routine called above
         }
       } 
     }
         
    else if ((Cloud==true) && (IsStorm==false)){
        if (StormAdvance==false){//use millis tracker to run this loop every 2 seconds
            return;
        }
        StormAdvance=false;//reset to false when true so we run this once, until time advance is true again
        if (elapsedTime>=CloudEnd){
            ClearSky(CloudCover, CloudEnd); 
            return;
        }
        
        /*Use fractional intensity to set minimum value for any channel.  Dimming is proportional to actual intensity output 
         and constrained by flicker point.  Random walk uses static variable "CloudCover" constrained to 0-100 to represent fractional intensity (i.e. (1-(CloudCover/100))*Insolation SetPoint 
         is how the current cloud intensity is set, i.e. cloud cover of 90 gives 10% insolation setpoint unless below flicker in which case = flicker*/
        if (loopCount==1){
          PriorCloudCover=CloudCover; //e.g. PriorCloudCover=CloudCover with no float math to screw things up
          LastStepSize=StepSize;
          StepSize=(random(5,21));// in Percent% (0-100) This is how much light intensity will change over the loop count interval (this actual time is dependent upon the call frequency of StromAdvance as set in the loop)
          if ((random(0,2)!=1)) StepSize=-(StepSize);
          if ((CloudCover+StepSize)>=100){//cannot shut off lights more than 100% so limit here
            StepSize=(100-CloudCover);//
            Counter++;
          }
          else if ((CloudCover+StepSize)<=0){//cannot be brighter than 100% so since were in a cloud dont "limit" it but reflect it back down
            StepSize=-(StepSize);
            if (Counter>=50) Counter-=random(-1,2);//since we got bright... lets further delay and randomize storm occurence  
          }
          CloudCover=CloudCover+StepSize;
        }

        if ((Counter>=60) && ((CloudEnd-elapsedTime)>=300)) {//if Counter (indexes when cloud cover reaches 100) has accumulated and we still have time lets make a storm
        //to change the frequency of storms increase or decrease the number comparison for counter in the if statement above (larger #== less storms).
        //if you change counter comparison here change it in the next loop as well
           if (StormCount>=1){//if we can have storms in this cloud (random- statisticly 1/3 clouds = no storm, 1/3 = 1 possible storm, 1/3 = 2 possible storms)
             byte RandomStorm;
             RandomStorm=random(0,11);//this randomizes for longer clouds without storm, avg cloud is much longer prior to storm occuring- thus short clouds will not generally have a storm
               if (RandomStorm>=4){
                 StormCount-=1;//count down by 1 the number of storms in this cloud- this will not roll the byte since the loop requires it to be at least 1 to ever subtract here. 
                 Counter=0;//reset this variable since Storm loop uses it as well.
                 int LongestStorm;//used to pass max possible time to storm if loop from cloud loop within weather function
                 LongestStorm=(CloudEnd-elapsedTime);
                 Severity=StartStorm(LongestStorm, IsStorm, StormEnd);
                 loopCount=1;//reset counting loop for the storm
               } 
           }
        }
        else if ((Counter>=60) && ((CloudEnd-elapsedTime)<300)){
           Counter=0;//just reset the counter (does not really matter in this case but its clean)
        }
        
        for (int a=0;a<8;a++){
            if (ChannelValue[a]==0) TrueIntensity[a]=0;// if were in an evening storm dont reset intensity (it would go to flicker point and possibly flicker)
            else if (DimOrder[a]==0){
                TrueIntensity[a]=(flicker[a]+(((float)(ChannelValue[a]-flicker[a]))*(1-((CloudCover-(StepSize-(StepSize/4)*loopCount))/100))));
            }
            else if (DimOrder[a]==1){
                TrueIntensity[a]=(flicker[a]+(((float)(ChannelValue[a]-flicker[a]))*(1-((PriorCloudCover-(LastStepSize-(LastStepSize/4)*loopCount))/100))));
            }     
         }
         loopCount++;
         if (loopCount>4) loopCount=1;
    }  
    //enable a flag sent from controller to triger a storm, i.e. IsStorm=true
    // set channel intensities for all but white with random walk continuing from above using static variable so should be seamless
    else if (((Cloud==true) && (IsStorm==true)) || ((Cloud==false) && (IsStorm==true))){
        //current else statement covers possibility of triggering storm from controller (i.e. not coming out of a cloud) but remember you need to flag wtrigger as TRUE when you do this
        if (StormAdvance==false){//Every 1 second duing a storm change intensity, clouds are movin fast baby
           return;
        }
        
        StormAdvance=false;//reset so we run again in 1 second.
        
       if (elapsedTime>=StormEnd){ //if were done with the storm we need to stop this loop, but were probably still cloudy so dont mess with that here
            IsStorm=false;
            Counter=0;
            return;
        }
        if (loopCount==1){
          PriorCloudCover=CloudCover; //e.g. PriorCloudCover=CloudCover with no float math to screw things up
          LastStepSize=StepSize;
          StepSize=(random(5,21));// in Percent% (0-100) This is how much light intensity will change over the loop count interval (this actual time is dependent upon the call frequency of StromAdvance as set in the loop)
          if ((random(0,2)!=1)) StepSize=-(StepSize);
          if ((CloudCover+StepSize)>=100){//cannot shut off lights more than 100% so limit here
            StepSize=(100-CloudCover);
            Counter++;
          }
          else if ((CloudCover+StepSize)<=0){//cannot be brighter than 100% so since were in a cloud dont "limit" it but reflect it back down
            StepSize=-(StepSize);
            if (Counter>=2) Counter-=random(0,2);//since we got bright... lets further delay and randomize strike occurence    
          }
          if (Counter>(Severity+2)) Counter=0;//allow if to accumulate on ocassion to train strike sequences 2-3 in a row but then dump it 
          CloudCover=CloudCover+StepSize;
        }
   
        if ((Counter>=(Severity+random(-1,4))) && (StrikeNow==false)) {//this is where a storm is triggered.  Counter indexes when cloud cover reaches 100 on the random walk
        //to change the frequency of lightning strikes increase or decrease the number comparison for counter in the if statement above (larger #== less storms).
          byte RandomStriker;
          RandomStriker=random(1,11);
          if (RandomStriker>4){
            StrikeNumber=(random(2,11)); //random high =x-1 so max strike =12 each strike requires a duration and a delay thus StrikeMaster is 18 positions
            //ensure the array is zeroed out past the last position required for this strike pattern so each pattern is only as long as generated
            //Array is in pairs, position in arry of (0,1) (2,3) etc as strike (delay,duration)
            for (byte a=0;a<20;a++){
                if (a>=(StrikeNumber*2)){
                    StrikeMaster[a]=0;
                }
                if (a%2==0){
                   if (a==0){
                      StrikeMaster[a]=random(300,1601);//no need for random here but I am leaving it since I wrote it that way.  This must be independent from a=2,4,6 etc...
                    }
                    else {
                       StrikeMaster[a]=(StrikeMaster[(a-2)]+random(200,1401));//position 0,2,4,6,8.. is strike delay
                    } 
                 }
                 else if(a%2!=0){
                    StrikeMaster[a]=random(50,110);//position 1,3,5,7,9... is strike duration (I tried real lightning strike durations and its too short this is adjusted for visual effect
                 }
            }
            StrikeNow=true; //Trigger to start strike sequence in loop
            StrikeStart=millis();//set timer to "zero" now- sequence will start in loop after this function
            StrikeCount=0;
          }
          Counter=0;
        }
        
        if (Severity>5){
          for (int a=0;a<8;a++) {
              if (ChannelValue[a]==0) TrueIntensity[a]=0;
              else if (Wchannel[a]==1){//if were in a storm but not a severe storm constrain whites to 50% of Insolation intensity
                if (DimOrder[a]==0){
                      TrueIntensity[a]=(flicker[a]+((((float)(ChannelValue[a]-flicker[a])/4))*(1-((CloudCover-(StepSize-(StepSize/3)*loopCount))/100)))); 
                  }
                  else if (DimOrder[a]==1){
                      TrueIntensity[a]=(flicker[a]+((((float)(ChannelValue[a]-flicker[a])/4))*(1-((PriorCloudCover-(LastStepSize-(LastStepSize/3)*loopCount))/100))));
                  }
              }
              else if (Wchannel[a]==0){//if were blue, we chase as for a cloud
                  if (DimOrder[a]==0){
                      TrueIntensity[a]=(flicker[a]+(((float)((ChannelValue[a]-flicker[a])))*(1-((CloudCover-(StepSize-(StepSize/3)*loopCount))/100)))); 
                  }
                  else if (DimOrder[a]==1){
                      TrueIntensity[a]=(flicker[a]+((((float)(ChannelValue[a]-flicker[a])))*(1-((PriorCloudCover-(LastStepSize-(LastStepSize/3)*loopCount))/100))));
                  }
              }    
          }
        }
        else if (Severity<=5){// severe storms occur throughout the day, but EVERY storm after sunset is severe...
          for (int a=0;a<8;a++) {
              if (ChannelValue[a]==0) TrueIntensity[a]=0;
              else if (Wchannel[a]==1){//if were white we need to be off in a storm
                TrueIntensity[a]=0;
              }
              else if (ChannelValue[a]==0){//if this light channel is dark... e.g. after sunset for this channel- it produces no cloud effect
                  TrueIntensity[a]=0;
              }
              else if (Wchannel[a]==0){//if were not shut off in a strom and not after our daylight period (this channel) then we produce storm light sequences.
                  if (DimOrder[a]==0){//if we dim first... do it
                      TrueIntensity[a]=(flicker[a]+(((float)((ChannelValue[a]-flicker[a])))*(1-((CloudCover-(StepSize-(StepSize/3)*loopCount))/100)))); 
                  }
                  else if (DimOrder[a]==1){//else we dim second
                      TrueIntensity[a]=(flicker[a]+((((float)(ChannelValue[a]-flicker[a])))*(1-((PriorCloudCover-(LastStepSize-(LastStepSize/3)*loopCount))/100))));
                  }
              }//end of CWHchannel==0 being true
           }//end of for loop in severity <5 == true loop
        }//end severity compairson loop no more else statements
       
        loopCount++;
        if (loopCount>3) loopCount=1;
    }//end of storm if loop
}//End Weather function

//CloudStart drops light intensity to 50% of whatever daylight setting is to start the cloud at 50
int CloudStart(long StartTime){
    byte elapsed;
    elapsed=(elapsedTime-StartTime);//counts up since we start this at elapsedTime=StartTime and StartTime is fixed
    for (byte a=0; a<8; a++){ 
      TrueIntensity[a]=(flicker[a]+(((float)((ChannelValue[a]-flicker[a])))*(1-(elapsed*2.5)/100)));
    if (elapsed>=20);
      Cloud=true;//start the cloud
    }
    return 50;//set CloudCover to 50 
}//end CloudStart function

//StartStorm sets up duration and severity of storm. Its currently limited to 90-600 sec in length- it will rarely be lower than 3 minutes
byte StartStorm(int MaxLength, boolean& trigger, long& EndTime){
      byte LightningIntensity;
      int StormDuration;
      MaxLength-=120;//remove 2 mins from longest storm so that we end up with 2 minutes of cloud after the storm before the sky clears to daylight
      if (MaxLength>720){
         MaxLength=720;//modify local variable
         StormDuration=random((MaxLength/3),(MaxLength+1));
         EndTime=(elapsedTime+StormDuration);//Set by reference StormEnd static variable in weather
      }
      else {
         StormDuration=random((MaxLength/2),(MaxLength+1));
         EndTime=(elapsedTime+StormDuration);//Set by reference StormEnd static variable in weather
      }
      if (elapsedTime<midDay){
         LightningIntensity=random(3,11);//morning storms are generally less severe
      }
      else if (elapsedTime>midDay){//afternoon storms are more likely to be severe (every 10-15 sec or less) to about once in a minute or maybe less
         if (elapsedTime>(set-rise)){//Storms after sunset are always severe... it just looks too cool!
           LightningIntensity=3;
         }
         else {
         LightningIntensity=random(3,8);
         }
      }
      trigger=true;
      return (LightningIntensity);
}
//End Storm Start Function
//Similar to Cloud start but in reverse... now ramp intensity from wherever we were at the end of the cloud to the value set by Insolation
void ClearSky(int CloudPercent, long TerminationTime)
{
    byte elapsed=(elapsedTime-TerminationTime);//Counts up from the scheduled end of the cloud in seconds
    float slope=(CloudPercent/30);//Just calculate how much to increment every second to go from CloudCover to clear sky (CloudCover of zero)
    float LightAdvance;
    LightAdvance=(CloudPercent-(slope*elapsed));//were reducing CloudCover from start to zero over 10 seconds.
    for (byte a=0; a<8; a++){ 
    TrueIntensity[a]=(flicker[a]+(((float)(ChannelValue[a]-flicker[a]))*(1-(LightAdvance/100)))); 
    }
    if (elapsed>=30){//at this point lights are back to full Insolation setting so cancel the cloud and start waiting for the next one
        Cloud=false;//stop the cloud we are now outside of a true condition in the if loop so it will now stay false and lights are back on
        IsStorm=false;//just to be redundant this is not called from a storm... 
    }
}//End Clear Sky function

byte MoonPhase()
{
   int m,d,y;
   int yy,mm;
   long K1,K2,K3,J,V;
   byte PWMvalue;
   m = month();
   d = day();
   y = year();
   yy = y-((12-m)/10);
   mm = m+9;
   if (mm>=12) mm -= 12;
   K1 = 365.25*(yy+4712);
   K2 = 30.6*mm+.5;
   K3 = int(int((yy/100)+49)*.75)-38;
   J = K1+K2+d+59-K3;
   V = (J-2451550.1)/0.29530588853;
   V -= int(V/100)*100;
   V = abs(V-50);
   PWMvalue = 4*abs(50-V);  // 5.12=100%    4=~80%
   //pinMode(lowATOPin,OUTPUT);
   //return (PWMvalue*100)/255; //output is 0-100
   return PWMvalue;//output is 0-255 
}

//********************** DO NOT MESS WITH THIS UNLESS YOU KNOW WHAT YOUR DOING****************************
//THE CODE BELOW THIS copied directly from the SWFLTEK Epherma library constructed by Michael Rice. 
//this code is being used freely with attribution to Micahel Rice in accord with his request
//  A big thank you for these library functions.  Its great! 


//convert degrees to seconds of arc


// decimal degrees
long ddToSeconds(float dd){
   return dd * 3600.0;
}

//Degrees, minutes, seconds
long dmsToSeconds(int d, unsigned char m, unsigned char s){
long ret;

   ret = labs((long)d);
   ret = ret * 3600L + 60L * m + s;
   ret = (d<0L) ? -ret : ret;
   return ret;
}
/* ------------------------------------------------------------------------------------------------
   'Equation of Time'
   We use the 'short form equation, which has a theoretical accuracy of about 40 seconds.
   The returned value is in seconds.
*/
int equation_of_time(unsigned long dt){
double t;

   dt -= 192540UL; // refer to Jan 3 2000 05:29 (first periapsis)
   dt %= _tropical_year;
   t = dt;
   t /= _tropical_year;
   t *= 6.283185307179586;
   t = -459.27672 * sin(t) + 575.333472 * sin(2.0 * t + 3.588414);
   return t;
}

/*
   'Solar Noon' adjusts the passed time stamp to the time (GMT) of local solar noon.
   The accuracy is about 40 seconds (set by the equation of time).
*/
void SolarNoon(unsigned long * dt){
long r;

   // Set stamp to noon GMT
   *dt /= 86400UL;
   *dt *= 86400UL;
   *dt += 43200UL;

   // adjust for equation of time, at noon GMT
   *dt -= equation_of_time(*dt);

   // rotate to our longitude
   r = longitude / 15L;
   *dt -= r;
}

/* -----------------------------------------------------------------------------------------------
   'Solar Declination'
   Returns declination in radians
   Accurate to within 50 arc-seconds
*/

double SolarDeclination(unsigned long dt){
double y;

   dt %= _tropical_year;
   y = dt;
   y /= _tropical_year; // fractional year
   y *= 6.283185307179586;
   y=0.006918-0.399912*cos(y)+0.070257*sin(y)-0.006758*cos(y*2)+0.000907*sin(y*2)-0.002697*cos(y*3)+0.00148*sin(y*3);
   return y;
}

/* ------------------------------------------------------------------------------------------------
   Return the period between sunrise and sunset, in seconds.
   At high latitudes around the time of the solstices, this could be zero, or all day.
*/
unsigned long daylightseconds(unsigned long dt){
float l, d, e;
long n;

   d = -SolarDeclination(dt); // will be positive in Northern winter
   l = latitude / _sec_rad; // latitude in radians

   e += 60.0 * l * tan(l + d); // latitudinal error
   d = tan(l) * tan(d); //

   if(d>1.0) return 86400UL;
   if(d < -1.0) return 0UL;

   d = acos(d);
   d /= _zenith;

   n = 86400UL * d;
   n += e;
   return n;
}


/* ------------------------------------------------------------------------------------------------
   Modify the passed time stamp to the time of sunrise (or sunset if 'set' is non-zero).
   Returns 0 to signal 'normal' completion. If the position is in a polar circle, 1 will be
   returned if the sun is above the horizon all day, and -1 if the sun is below the horizon
   all day.

*/
char SunRiseSet(unsigned long * dt, char set){
unsigned long daylen;

   daylen = daylightseconds(*dt);
   if(daylen == 86400UL) return 1;   // there is no 'night' today (midnight sun)
   if(daylen == 0UL) return -1; // there is no 'day' today

   *dt /= 86400UL;
   *dt *= 86400UL;
   *dt += 43200UL; // set the time stamp to 12:00:00 GMT

   *dt -= daylen / 2; //        sunrise at the prime meridian
   if(set) *dt += daylen; //     sunset at the prime meridian

   *dt -= equation_of_time(*dt);

   //*dt -= longitude / 15.0; // rotate to our own meridian

   return 0;
}
// 'short' forms of SunRiseSet
char SunRise(unsigned long* when){
    return SunRiseSet(when, 0);
}
char SunSet(unsigned long* when){
    return SunRiseSet(when, 1);
}




void loop()
{
    ReefAngel.StandardHeater( Port3,820,825 );
    ReefAngel.StandardLights( Port7,21,0,7,0 );
    ReefAngel.SingleATO( true,Port1,90,0 );
    ReefAngel.WavemakerRandom(Port5,15,45);
    ReefAngel.WavemakerRandom1(Port6,15,45);
    
    ////// Place your custom code below here
  
static unsigned long feeding = 0;

if ((now()%SECS_PER_DAY==28800) || (now()%SECS_PER_DAY==50400) || (now()%SECS_PER_DAY==72000)) //if it is 8am or 2pm or 8 pm
{
ReefAngel.FeedingModeStart(); //START FEEDING MODE
}

if (ReefAngel.DisplayedMenu==FEEDING_MODE)
{
 if ( feeding == 0 ) 
 {
 feeding = now(); //set the time of the start of feeding to variable feeding
 }

 if ((now()-feeding>=60) && (now()-feeding<=61)) //if between 60 and 61 seconds has past
 {
 ReefAngel.Relay.On(Port8); //TURN FEEDER RELAY ON
 }
 else 
 {
 ReefAngel.Relay.Off(Port8); //TURN FEEDER RELAY OFF
 }
} else {
if ( feeding > 0 ) {
feeding = 0;
}
}




    elapsedTime=(now()-newDay);//Elapsed time is seconds from midnight of today- local processor time.
    wdt_reset();
    if (cmdnum!=255){
        ProcessCMD(cmdnum,datanum);    
        cmdnum=255;
        datanum=255;
    }
    
    if (dow!=day()){ //used to see that were in a new day and need to recalculate sunrise and sunset
      CalSun();
      dow=day();
    }
  
    //Use millis to enable tracking of time interval
    if ((millis()-lastmillis)>=100){
        lastmillis=millis();
        counter+=1;
        StormAdvance=true;
        //now a bunch of stuff that may or may not be true at the same time but that all needs to happen when its true
        if (counter==0){
          InsolationAdvance=true;//so that it runs on start up to provide light immediately 
        }  
        if (counter%30==0){
          InsolationAdvance=true;
        }
        if (counter==210) counter=0; 
    }     

   if (InsolationAdvance==true) Insolation();//calculate clear sky solar intensity as the day advances
   Weather();//run the weather overlay (cloud, storm)
   //check to see if were need to have a lightning strike
    if (StrikeNow==true){
       if ((millis()-StrikeStart)>=StrikeMaster[(StrikeCount*2)]){//check if time has passed the delay (position 0,2,4,6,8 etc in StrikeMaster)-StrikeCount is indexed up by 1 after each strike so we see positions 0,2,4,6,etc in sequence
          byte intensity;
          intensity=random(180,256);// this little bit should generate a randomly bright flash variation between the series of flashes in StrikeMaster
              for (byte b=0; b<6; b++){
                  if (StrikeChannel[b]==1) analogWrite(PWMports[b],intensity);// set all strike channels to intensity of strike
              }
          delay(StrikeMaster[((StrikeCount*2)+1)]);//index to +1 position in array from 0,2,4, etc to 1,3,5 etc
          StrikeCount++;//so that the next time we look at elapsed time were looking at the right array position
          if (StrikeCount==(StrikeNumber-1)){
            StrikeNow=false;
            StrikeCount=0;
          }
       }
    }
    for (byte a=0;a<6;a++){//using all prior mods to light intensity (Insolation-->Cloud-->Storm) lets make some light
      analogWrite(PWMports[a],TrueIntensity[a]);//dont change this to 8 to refelct array for channels.. we only have 6 here!
    }

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

    // This should always be the last line
    ReefAngel.AddWifi();
    ReefAngel.ShowInterface();
}

void DrawCustomMain()
{
    int x,y;
    char text[10];
    // Parameters
#if defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 20, ReefAngel.Params,
    ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue() );
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 20, ReefAngel.Params );
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
    pingSerial();

    // pH Expansion
    ReefAngel.LCD.DrawText( COLOR_MEDIUMSEAGREEN,DefaultBGColor,15,66, "PHE:" );
    ReefAngel.LCD.DrawSingleMonitor( ReefAngel.Params.PHExp,COLOR_MEDIUMSEAGREEN,39,66, 100 );    
    pingSerial();

    // Main Relay Box
    byte TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox( 12, 92, TempRelay );
    pingSerial();

    // Date and Time
    ReefAngel.LCD.DrawDate( 6, 122 );
    pingSerial();
}

void DrawCustomGraph()
{
}
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Weather Simulation for Dimming expansion module

Post by dlplunkett44 »

nevermind, figured it out. Didn't need to have it in the pde as well.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Weather Simulation for Dimming expansion module

Post by dlplunkett44 »

After uploading this to my main unit, the screen just stays dark. What did I do wrong?
rufessor
Posts: 293
Joined: Tue Oct 25, 2011 7:39 am

Re: Weather Simulation for Dimming expansion module

Post by rufessor »

Its not written to run on the main....

It is doing things like hard coded write to PMW channels which will do nothing on the main since it does not have that...

I have made an effort and have said in the past that I am working on it- in working on it a bit it became obvious (after spending some hours trying) that I was not going to be able to easily get it ported to OO code and I stopped because even getting it set up to test it out was something I simply have not done before.

Since there appears to be an ongoing interest and implementation of this code, lets see if someone has time to help. If thats the case then everyone will benefit. I am happy to spend time with a more experienced person to basically work together using their skills in porting and my knowledge of how the code goes together to figure out where to split this up.


IF your knowledgable about the RA head unit and how its making calls to the dimming module to run the light intensities, I can show you pretty much where you need to edit to change the existing code so that it runs the PWM module. However, depending on which includes you have in your PDE code for the head, it may becomes somewhat complicated. Up to you... I am more interested in working with someone who can help pull this into the library distribution as this will solve the problem for everyone regardless of expertise.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Weather Simulation for Dimming expansion module

Post by lnevo »

No, I don't have the bandwidth at this time. I believe binder had offered to help with the OO aspect.

The SunLocation class has a lot of the SWFLTEK code in it and could probably be used as a reference. The link is in the first or second post on my INO page in my signature.
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Weather Simulation for Dimming expansion module

Post by binder »

lnevo wrote:No, I don't have the bandwidth at this time. I believe binder had offered to help with the OO aspect.

The SunLocation class has a lot of the SWFLTEK code in it and could probably be used as a reference. The link is in the first or second post on my INO page in my signature.
yeah, I can help out with the OO part of code and getting it set up as an includable library for the controller.
I have not looked back at the current code yet. But if it's currently working in a state that you are happy with, I can start with that code and see what all i can put together making references to the sunlocation class as well.

So, if someone would either PM me the current code or point me to link for the current code and just summarize what it needs to do (sounds like just have it run off of the headunit ports or make calls to control the pwm expansion ports) and the possible things that need to be configured (duration, chance, etc), then I should be able to start hashing something out for people.

Sent from my Nexus 7
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Weather Simulation for Dimming expansion module

Post by dlplunkett44 »

Binder, that would be awesome! I think the working code is on the first page. I would love to help with this but my coding is not up to par yet. It needs to be able to run off of the main controller and run the pwm expansion. The original code was meant to just run the pwm ports 0 - 5 of course, but it would be great to be able to control 2 or more pwm expansions. I don't believe this would require any more work, but I'm not sure....
rufessor
Posts: 293
Joined: Tue Oct 25, 2011 7:39 am

Re: Weather Simulation for Dimming expansion module

Post by rufessor »

Kurt-

I am sending you a PM-

dlplunkett44

Controlling more than 1 PMW dimming module is possible- but it means modifying a fair number of arrays in the code which is basically trivial. However, it also would require a beta tester to deal with trouble shooting the code. Since I wrote it with the idea that we could control only 1 dimming module, and since its working this way for now and will capture the vast majority of users- I am going to start here and PM back and forth with Kurt so he can package this up into a module. Once thats working, then its basically "Easy" to start thinking about how to do this and you, or anyone else could grab the code from the library and changes can be made locally to get it working. So long as nothing major changed in terms of how we get this packaged in (e.g. we only changed the number of addressable PMW ports) I do not see why that could not then be passed onto Kurt to basically replace the first run- single PWM module code in the library. But since I only have a single PMW module, and I do NOT have a RA+ its going to be hard for me to help test code beyond my equipment capabilities.

We will post here as we get code together thats worth testing, as I suspect that we will want a few guinea pigs to try this on the main before it gets actually put into the distribution= to avoid headaches with a bunch of people breaking stuff all at once and no one having working lights!
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Weather Simulation for Dimming expansion module

Post by binder »

I got the PM. I will be reading through it over the next few days and start coming up with some ideas as to what all needs to be done.

Sent from my Nexus 7
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Weather Simulation for Dimming expansion module

Post by dlplunkett44 »

Consider me a guinea pig! I only have one PWM expansion now, but down the road I will need more channels and will approach this at that time. Thanks!
TanksNStuff
Posts: 188
Joined: Fri Dec 30, 2011 6:57 am

Re: Weather Simulation for Dimming expansion module

Post by TanksNStuff »

I would be happy to be a guinea pig for this project too.

Not sure if this makes a difference or not, but I have an analog version of the dimming module so it works for my Apollo Reef LED's. I currently just run it with the parabola function for my 4 channels... although I'm able to change any parameters (start/end % and/or times) via the android app on the fly, so I think this weather sim code will work for me too.

While I'm not an expert when it comes to coding, I do have a custom code running that's a bit more complicated than most are running and I feel that I could help track down any errors.
rufessor
Posts: 293
Joined: Tue Oct 25, 2011 7:39 am

Re: Weather Simulation for Dimming expansion module

Post by rufessor »

That sounds great- I am currently the weak link in the chain moving forward. I have been to busy lately to take even a few hours and ensure that what Kurt gets is exactly what we want to see as a library code. I have revised the code that protects against photo bleaching during long summer days and ensures a user specified minimum light on period on winter days where rise and set may be too short to ensure adequate light over the tank. I want to make this optional so that those who want the rise and set times to exactly match compited can do so, and suffer the consequences if they end up bleaching or browning, or have it so that you simply instruct it what you minimum light cycle must be give. your max intensity settings are so that in the winter it adds time to get that light period. During the summer I am using a scaling routine where the percent of day lenght beyond the desired light period is used to subtly scale back max intensities so that you get correlation with rise and set to their exact calculated values, but the tank does not bleach. I have been testing this for a year now and want to adjust one thing- check the rest of the code and send it on to Kurt.

Sorry for being the weak link... it will happen soon
TanksNStuff
Posts: 188
Joined: Fri Dec 30, 2011 6:57 am

Re: Weather Simulation for Dimming expansion module

Post by TanksNStuff »

Trust me, being the President of the reefing club I'm in (NJ Reefers) I know what it's like to juggle time between your home life and volunteering on a community project.

This project may not even be this far along if you hadn't already done the groundwork you've done so far. A little more time won't kill us, heh.
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Weather Simulation for Dimming expansion module

Post by binder »

no worries here. my schedule is hectic as well. that's just the "fun" with things. :)
89delta
Posts: 163
Joined: Mon Oct 15, 2012 7:21 pm
Location: Leesburg, GA

Re: Weather Simulation for Dimming expansion module

Post by 89delta »

Hi all,

I'm actually using this code with my arduino uno with great success. I was wondering if it's possible to add coding for coral acclimation for x days with the max say 65% gradually ramping up to 100% again across the x days. The acclimation part would be initialized by a push button. Thanks.
weasel440
Posts: 1
Joined: Wed Feb 19, 2014 12:31 pm

Re: Weather Simulation for Dimming expansion module

Post by weasel440 »

Hello, I'm new here. I tried out the sketch, I'm using a arduino uno but when I go to the serial monitor it don't show anything? Anyone else experience this?

And also is there a way to turn off the storm function - and still have the cloud function?
ReEfnWrX
Posts: 234
Joined: Tue Nov 05, 2013 8:40 am
Location: Houston TX

Re: Weather Simulation for Dimming expansion module

Post by ReEfnWrX »

89delta wrote:Hi all,

I'm actually using this code with my arduino uno with great success. I was wondering if it's possible to add coding for coral acclimation for x days with the max say 65% gradually ramping up to 100% again across the x days. The acclimation part would be initialized by a push button. Thanks.

I have created Dimming Acclimation code.

The first post in this thread will walk you through it.
http://forum.reefangel.com/viewtopic.php?f=12&t=4193

I have not created any menu options to begin acclimation. It is started by setting the AcclDay to the same value you have chosen for your AcclDuration(Total days in accl cycle).
Image
User avatar
Sacohen
Posts: 1833
Joined: Sun Apr 21, 2013 6:25 am
Location: Davie, FL

Re: Weather Simulation for Dimming expansion module

Post by Sacohen »

Did this ever get ported to the head unit with any luck?
I'm working on getting my LED's running and would love to have a storm mode set up, but I have no idea how to dow this.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Weather Simulation for Dimming expansion module

Post by rimai »

If it is just the lightning you are trying to achieve, you can use this:
http://forum.reefangel.com/viewtopic.php?f=14&t=288
Roberto.
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Weather Simulation for Dimming expansion module

Post by binder »

Sacohen wrote:Did this ever get ported to the head unit with any luck?
I'm working on getting my LED's running and would love to have a storm mode set up, but I have no idea how to dow this.
i havent gotten a response back with the base code to try to turn into a library because i was told there were changes made from what was originally posted. so theres not been any progress that im aware but thats not saying much anymore. :-)


Sent from my iPad mini
User avatar
Sacohen
Posts: 1833
Joined: Sun Apr 21, 2013 6:25 am
Location: Davie, FL

Re: Weather Simulation for Dimming expansion module

Post by Sacohen »

Ok. Thanks

Sent from my HTC One VX using Tapatalk
User avatar
Sacohen
Posts: 1833
Joined: Sun Apr 21, 2013 6:25 am
Location: Davie, FL

Re: Weather Simulation for Dimming expansion module

Post by Sacohen »

rimai wrote:If it is just the lightning you are trying to achieve, you can use this:
http://forum.reefangel.com/viewtopic.php?f=14&t=288

What I would like to do is the following...

1) Sunrise/sunset (not necessarily accurate to the actual sunrise sunset)
2) Random Lightning
3) Random Cloud cover

Possibly Moonlight cycle later. That I would want tied to the actual Moon Phase.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Weather Simulation for Dimming expansion module

Post by lnevo »

Steve,

The Sunrise/Sunet you could get from my SunLocaltion class that binder helped to isolate. The Moon cycle, you could also get from my Moon class. This would give you daily rise/set moontime or you could use your own schedule and use MoonPhase() as the parameter.

Random lightning and random cloud cover could then just be done with the standalone weather effects that Roberto linked to.
User avatar
Sacohen
Posts: 1833
Joined: Sun Apr 21, 2013 6:25 am
Location: Davie, FL

Re: Weather Simulation for Dimming expansion module

Post by Sacohen »

Ok. Cool.

Sent from my HTC One VX using Tapatalk
User avatar
heatdissipation
Posts: 52
Joined: Wed Aug 14, 2013 5:25 am

Re: Weather Simulation for Dimming expansion module

Post by heatdissipation »

Will this program work with sixteen channels, Roberto is making me a custom 16 channel expansion and this is exactly what I would like to do. How difficult would it be to use sixteen channels.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Weather Simulation for Dimming expansion module

Post by lnevo »

The code was meant to live on the old dimming modules. However the code does nothing special that couldnt be done with 16 channels, but the code will take a bit of tweaking.

I have a standalone class that determines sun rise/set and roberto has a weather effect somewhere thats a lot simpler
User avatar
heatdissipation
Posts: 52
Joined: Wed Aug 14, 2013 5:25 am

Re: Weather Simulation for Dimming expansion module

Post by heatdissipation »

Ya. I just got done reading all nine pages and came to that conclusion also. I'm reading both of those codes you just mentioned now. Just trying to find the time with my work schedule to compile the different codes I need is a task in and of itself.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Weather Simulation for Dimming expansion module

Post by lnevo »

Easier to add a feature at a time and take it slow :) Same as reefing to me.. No good code happens quickly.
Post Reply