Over my head

Do you have a question on how to do something.
Ask in here.

Posts: 7
Joined: Sat Mar 29, 2014 4:05 pm
PostPosted: Sat Dec 24, 2016 2:14 pm
I have been using RA for a while, with no background in programming, and for the most part I have been able to piece together enough to make it work, until now. I am really struggling adapting Inevo's code to what I want, and am hoping one of you kind souls will help me out.

I basically want to adapt Inevo's Vortech control, especially the custom modes and influence of the tide, and I thought the calculating the evaporation rate would be really cool as well. I also want to get the sunrise/set and moonrise/set code to work, since I hope to upgrade to controllable LEDs in the future.

I get it to compile, and it is running ok, but it doesn't seem to work as I expected.

1. I seem to have an extra Relay on my dashboard now, and I don't know why.
2. When in custom mode the vtmode stays at 1. Looking at the code I expected it to change every 6 hours.
3. Evaporation stays at 0.
4. The only way I can get the sunrise offset to wok is by hard coding the value; it doesn't seem to work from the memory.

There's probably a lot wrong with the code, so any help would be greatly appreciated!

Here's 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 <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 <SunLocation.h>
#include <Tide.h>
#include <Moon.h>


     // Won't compile without this...
        // ReefAngel.DCPump.UseMemory=true;
        // Custom menus
        #include <avr/pgmspace.h>
        prog_char menu1_label[] PROGMEM = "Refugium Light";
        prog_char menu2_label[] PROGMEM = "Feeding Mode";
        prog_char menu3_label[] PROGMEM = "Water Change";
        prog_char menu4_label[] PROGMEM = "Vortech Mode";
        prog_char menu5_label[] PROGMEM = "ATO Clear";
        prog_char menu6_label[] PROGMEM = "Overheat Clear";
        prog_char menu7_label[] PROGMEM = "PH Calibration";
        prog_char menu8_label[] PROGMEM = "WLS Calibration";
        prog_char menu9_label[] PROGMEM = "Date / Time";

        // Group the menu entries together
        PROGMEM const char *menu_items[] = {
        menu1_label, menu2_label, menu3_label,
        menu4_label, menu5_label, menu6_label,
        menu7_label, menu8_label, menu9_label
        };
       
 // Define Custom Memory Locations
        #define Mem_B_MoonOffset      100
        #define Mem_I_Latitude        108
        #define Mem_I_Longitude       110
        #define Mem_B_AcclRiseOffset  112
        #define Mem_B_AcclSetOffset   113
        #define Mem_B_AcclDay         114
        #define Mem_B_TideMin         117
        #define Mem_B_TideMax         118
        #define Mem_B_PumpOffset      119
        #define Mem_B_FeedingRF       120
        #define Mem_B_NightRF         121
        #define Mem_B_NightSpeed      122
        #define Mem_B_NightDuration   123
        #define Mem_B_NTMSpeed        124
        #define Mem_B_NTMDuration     125
        #define Mem_B_NTMDelay        126
        #define Mem_B_NTMTime         127
        #define Mem_B_LogATO          140
        #define Mem_B_LogPrevATO      141
        #define Mem_B_TideMode        143
        #define Mem_B_LightMode       160
        #define Mem_B_LightOffset     161
        #define Mem_I_RiseOffset      162
        #define Mem_I_SetOffset       164
        #define Mem_B_AcclActinicOffset     166
        #define Mem_B_AcclDaylightOffset    167
        #define Mem_B_RandomMode      168
        #define Mem_B_GyreOffset      169
        #define Mem_B_MoonMode        170
        #define Mem_B_LightsOffPerc   171
        #define Mem_B_FeedingSpeed    172
        #define Mem_B_WCSpeed         173
        #define Mem_B_EnableStorm     178
        #define Mem_B_ForceRandomTide 179

        #define Mem_B_PrintDebug      198
        #define Mem_B_ResetMemory     199

        void init_memory() {
          // Initialize Custom Memory Locations
          InternalMemory.write(Mem_B_MoonOffset,30);
          InternalMemory.write_int(Mem_I_Latitude,21);
          InternalMemory.write_int(Mem_I_Longitude,-73);
          InternalMemory.write(Mem_B_AcclRiseOffset,4);
          InternalMemory.write(Mem_B_AcclSetOffset,2);
          InternalMemory.write(Mem_B_AcclDay,0);
          InternalMemory.write(Mem_B_TideMin,10);
          InternalMemory.write(Mem_B_TideMax,20);
          InternalMemory.write(Mem_B_PumpOffset,80);
          InternalMemory.write(Mem_B_FeedingRF,true);
          InternalMemory.write(Mem_B_NightRF,false);
          InternalMemory.write(Mem_B_NightSpeed,35);
          InternalMemory.write(Mem_B_NightDuration,16);
          InternalMemory.write(Mem_B_NTMSpeed,60);
          InternalMemory.write(Mem_B_NTMDuration,5);
          InternalMemory.write(Mem_B_NTMDelay,15);
          InternalMemory.write(Mem_B_NTMTime,150);
          InternalMemory.write(Mem_B_TideMode,0);
          InternalMemory.write(Mem_B_LightOffset,20);
          InternalMemory.write(Mem_B_LightMode,1);
          InternalMemory.write_int(Mem_I_RiseOffset,5);
          InternalMemory.write_int(Mem_I_SetOffset,5);
          InternalMemory.write(Mem_B_AcclActinicOffset,100);
          InternalMemory.write(Mem_B_AcclDaylightOffset,100);
          InternalMemory.write(Mem_B_RandomMode,true);
          InternalMemory.write(Mem_B_GyreOffset,10);
          InternalMemory.write(Mem_B_MoonMode,1);
          InternalMemory.write(Mem_B_LightsOffPerc,1);
          InternalMemory.write(Mem_B_FeedingSpeed,3);
          InternalMemory.write(Mem_B_WCSpeed,25);
          InternalMemory.write(Mem_B_EnableStorm,true);

          InternalMemory.write(Mem_B_LogATO,0);
          InternalMemory.write(Mem_B_LogPrevATO,0);
         
          InternalMemory.write(Mem_B_ResetMemory,false);
        }


////// Place global variable code below here
        #define NUMBERS_8x16
       
        #define Var_Tide         0
        #define Var_LogATO       1
        #define Var_TideMode     2
               
        #define Level         75
        #define MinPWM        55
        #define OperatingPWM  75

        // Custom classes
        SunLocation sun;
        Tide tide;

        // Vortech Variables
        byte vtMode, vtSpeed, vtDuration;

        // Roberto Flow Variables
        long nummillis=5000;
        byte PWMValue=0;
        unsigned long lastmillis=millis();
        boolean override=false;

        #define Refugium           4
       
        // Needs to be global for DrawCustomGraph()
        int ScreenID=1;

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

        // Setup on controller startup/reset
      void setup()
      {
          // This must be the first line
          ReefAngel.Init();  //Initialize controller
          ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items)); // Initialize Menu
          ReefAngel.AddSalinityExpansion();  // Salinity Expansion Module
          ReefAngel.AddMultiChannelWaterLevelExpansion();  // Multi-Channel Water Level Expanion Module
   
          // Ports toggled in Feeding Mode
          ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port5Bit | Port7Bit;
         
          // Ports toggled in Water Change Mode
          ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port5Bit | Port7Bit;
   
          // Ports toggled when Lights On / Off menu entry selected
          ReefAngel.LightsOnPorts = 0;
   
          // Ports turned off when Overheat temperature exceeded
          ReefAngel.OverheatShutoffPorts = Port6Bit;
   
          // Use T1 probe as temperature and T2 as overheat
          ReefAngel.TempProbe = T1_PROBE;
          ReefAngel.OverheatProbe = T2_PROBE;

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

    // Ports that are always on
    ReefAngel.Relay.On( Port2 );
    ReefAngel.Relay.On( Port5 );
    ReefAngel.Relay.On( Port7 );
    ReefAngel.Relay.On( Port8 );

    ////// Place additional initialization code below here
   
    InternalMemory.WaterLevelMax_write(1800);
    ReefAngel.RF.UseMemory=false;
    randomSeed(now()/SECS_PER_DAY);
 
    Serial.println("Booting.");
    if (InternalMemory.read(Mem_B_ResetMemory))
    init_memory(); 
    ////// Place additional initialization code above here
}

void loop()
{
    ReefAngel.SingleATOLow( Port1 );
    ReefAngel.DayLights( Port4 );
    ReefAngel.StandardHeater( Port6 );
    ReefAngel.DCPump.UseMemory = true;
    //ReefAngel.DCPump.DaylightChannel = None;
    //ReefAngel.DCPump.ActinicChannel = Sync;
   
    ////// Place your custom code below here
 
      // Lighting and Flow
        SetSun();               // Setup Sun rise/set lighting
       // AcclimateLED();         // Apply acclimation dimming
        SetMoon();              // Setup Moon rise/set lighting
       // FillInMoon();           // Fill in 5% to 0% gap in main LEDs
       // LEDPresets();
       // CheckCloud();           //  Check for cloud and lightning.
       // UpdateLED();
        SetTide();              // Set High/Low tide properties
        SetRF();                // Set Vortech modes
        CheckATO();             // Calculate ATO reservoir evaporation
       
        RefugiumLight();        // Turn off refugium lights
 
      //Kalk stirrer on for 10 min per hour
      if (minute()< 10)
        {
        ReefAngel.Relay.On( Port3 );
        }   
        else
        {
        ReefAngel.Relay.Off( Port3 );
        }
 
       //  RobertoFlow
      PWMValue=OperatingPWM;
      if (ReefAngel.WaterLevel.GetLevel(2)==0)
        {
        PWMValue=77;
        }
        else
        {
          if (ReefAngel.WaterLevel.GetLevel(2)<Level-2)
          {
            override=true;
            lastmillis=millis();
            PWMValue+=(Level-ReefAngel.WaterLevel.GetLevel(2));
          }
          if (ReefAngel.WaterLevel.GetLevel(2)>Level+2)
          {
            override=true;
            lastmillis=millis();
            PWMValue-=(ReefAngel.WaterLevel.GetLevel(2)-Level);
          }
          if (millis()-lastmillis>nummillis && override)
          {
            override=false;
          }
          if (!override) PWMValue=OperatingPWM;
          if (ReefAngel.WaterLevel.GetLevel(2)>Level+10) PWMValue=MinPWM;
          PWMValue=constrain(PWMValue,MinPWM,100);
        }
      ReefAngel.PWM.SetActinic(PWMValue);
 
      // This should always be the last line
      ReefAngel.Portal( "gpsinger","8228" );
      ReefAngel.ShowInterface();
    }

void SetSun() {
  // Start acclimation routine
  int acclRiseOffset=InternalMemory.read(Mem_B_AcclRiseOffset)*60;
  int acclSetOffset=InternalMemory.read(Mem_B_AcclSetOffset)*60;
  byte acclDay=InternalMemory.read(Mem_B_AcclDay);
 
  // See if we are acclimating corals and decrease the countdown each day
  static boolean acclCounterReady=false;
  if (now()%SECS_PER_DAY!=0) acclCounterReady=true;
  if (now()%SECS_PER_DAY==0 && acclCounterReady && acclDay>0) {
    acclDay--;
    acclCounterReady=false;
    InternalMemory.write(Mem_B_AcclDay,acclDay);
  }
  // End acclimation

  // Add some customizable offsets
  sun.Init(InternalMemory.read_int(Mem_I_Latitude), InternalMemory.read_int(Mem_I_Longitude));
  int riseOffset=(-5);
  int setOffset=(-5);
 
  sun.SetOffset(riseOffset,(acclDay*acclRiseOffset),setOffset,(-acclDay*acclSetOffset)); // Bahamas
  sun.CheckAndUpdate(); // Calculate today's Sunrise / Sunset

  byte lightOffset=InternalMemory.read(Mem_B_LightOffset); // left right separation
  byte actinicOffset=InternalMemory.ActinicOffset_read();
 
  // Make sure light resets to zero at night.
  for(int i=0;i<4;i++) { ReefAngel.PWM.SetChannel(i,0); }
 
  switch(InternalMemory.read(Mem_B_LightMode)) {   
    case 0: {
      // Daylights
      ReefAngel.PWM.Channel0PWMSlope(lightOffset,0);
      ReefAngel.PWM.Channel2PWMSlope(0,lightOffset);
      // Actinics
      ReefAngel.PWM.Channel1PWMSlope(actinicOffset+lightOffset,actinicOffset);
      ReefAngel.PWM.Channel3PWMSlope(actinicOffset,actinicOffset+lightOffset);
      break;
    }
    case 1: {
      // Daylights
      ReefAngel.PWM.Channel0PWMParabola(lightOffset,0);
      ReefAngel.PWM.Channel2PWMParabola(0,lightOffset);
      // Actinics
      ReefAngel.PWM.Channel1PWMParabola(actinicOffset+lightOffset,actinicOffset);
      ReefAngel.PWM.Channel3PWMParabola(actinicOffset,actinicOffset+lightOffset);
      break;
    }
  case 2: {
      // Daylights
      ReefAngel.PWM.Channel0PWMSmoothRamp(lightOffset,0);
      ReefAngel.PWM.Channel2PWMSmoothRamp(0,lightOffset);
      // Actinics
      ReefAngel.PWM.Channel1PWMSmoothRamp(actinicOffset+lightOffset,actinicOffset);
      ReefAngel.PWM.Channel3PWMSmoothRamp(actinicOffset,actinicOffset+lightOffset);
      break;
    }
  case 3: {
      // Daylights
      ReefAngel.PWM.Channel0PWMSigmoid(lightOffset,0);
      ReefAngel.PWM.Channel2PWMSigmoid(0,lightOffset);
      // Actinics
      ReefAngel.PWM.Channel1PWMSigmoid(actinicOffset+lightOffset,actinicOffset);
      ReefAngel.PWM.Channel3PWMSigmoid(actinicOffset,actinicOffset+lightOffset);
      break;
    }
  }
}

void SetMoon() {
  byte offset=InternalMemory.read(Mem_B_MoonOffset);
 
  byte startD=InternalMemory.read(Mem_B_PWMSlopeStartD);
  byte endD=InternalMemory.read(Mem_B_PWMSlopeEndD);
  byte timeD=InternalMemory.read(Mem_B_PWMSlopeDurationD);

  byte startA=InternalMemory.read(Mem_B_PWMSlopeStartA);
  byte endA=InternalMemory.read(Mem_B_PWMSlopeEndA);
  byte timeA=InternalMemory.read(Mem_B_PWMSlopeDurationA);

  time_t onTime=ScheduleTime(Moon.riseH, Moon.riseM,0);
  time_t offTime=ScheduleTime(Moon.setH, Moon.setM,0);
  time_t offsetOnTime=ScheduleTime(Moon.riseH, Moon.riseM,0)-(offset*60);
  time_t offsetOffTime=ScheduleTime(Moon.setH, Moon.setM,0)-(offset*60);

  byte actRiseH=(offsetOnTime%SECS_PER_DAY)/SECS_PER_HOUR;
  byte actRiseM=((offsetOnTime%SECS_PER_DAY)%SECS_PER_HOUR)/60;
  byte actSetH=(offsetOffTime%SECS_PER_DAY)/SECS_PER_HOUR;
  byte actSetM=((offsetOffTime%SECS_PER_DAY)%SECS_PER_HOUR)/60;
 
  static byte mp=MoonPhase();
 
  if (mp!=MoonPhase()) {
    InternalMemory.write(Mem_B_PWMSlopeEndD,mp);
    InternalMemory.write(Mem_B_PWMSlopeEndA,mp);
    mp=MoonPhase();
  }
 
  moon_init(InternalMemory.read_int(Mem_I_Latitude), InternalMemory.read_int(Mem_I_Longitude));
 
  // Make sure light resets to zero at night.
  ReefAngel.PWM.SetDaylight(0);
  ReefAngel.PWM.SetActinic(0);
 
  switch(InternalMemory.read(Mem_B_MoonMode)) {   
    case 0: {
      // Daylights
      ReefAngel.PWM.SetDaylightRaw(PWMSlopeHighRes(Moon.riseH,Moon.riseM,Moon.setH,Moon.setM,startA,endA,timeA,0));
      ReefAngel.PWM.SetActinicRaw(PWMSlopeHighRes(actRiseH,actRiseM,actSetH,actSetM,startD,endD,timeD,0));
      break;
    }
    case 1: {
      ReefAngel.PWM.SetDaylightRaw(PWMParabolaHighRes(Moon.riseH,Moon.riseM,Moon.setH,Moon.setM, startA,endA,0));
      ReefAngel.PWM.SetActinicRaw(PWMParabolaHighRes(actRiseH,actRiseM,actSetH,actSetM, startD,endD,0));
      break;
    }
  case 2: {
      ReefAngel.PWM.SetDaylightRaw(PWMSmoothRampHighRes(Moon.riseH,Moon.riseM,Moon.setH,Moon.setM,startA,endA,timeA,0));
      ReefAngel.PWM.SetActinicRaw(PWMSmoothRampHighRes(actRiseH,actRiseM,actSetH,actSetM,startD,endD,timeD,0));
      break;
    }
  case 3: {
      ReefAngel.PWM.SetDaylightRaw(PWMSigmoidHighRes(Moon.riseH,Moon.riseM,Moon.setH,Moon.setM,startA,endA,0));
      ReefAngel.PWM.SetActinicRaw(PWMSigmoidHighRes(actRiseH,actRiseM,actSetH,actSetM,startD,endD,0));
      break;
    }
 
  }
}

void SetTide() {
  byte nightSpeed=InternalMemory.read(Mem_B_NightSpeed);
  byte tideMin=InternalMemory.read(Mem_B_TideMin);
  byte tideMax=InternalMemory.read(Mem_B_TideMax);

  // Set tide offsets
  tide.SetOffset(tideMin, tideMax);     
  // Set tide speed. Slope in/out of Night Mode
  tide.SetSpeed(PWMSlope(sun.GetRiseHour()-1,sun.GetRiseMinute(),
    sun.GetSetHour(),sun.GetSetMinute(),nightSpeed+tideMin,vtSpeed,120,nightSpeed+tideMin));

  // Show tide info on portal
  ReefAngel.CustomVar[Var_Tide]=tide.CalcTide();
}

void SetRF() {
  int ntmDelay=InternalMemory.read(Mem_B_NTMDelay)*60;
  int ntmTime=InternalMemory.read(Mem_B_NTMTime)*60;
  boolean nightRF=InternalMemory.read(Mem_B_NightRF);
  boolean feedingRF=InternalMemory.read(Mem_B_FeedingRF);
  static time_t t;

  ReefAngel.RF.FeedingSpeed=InternalMemory.read(Mem_B_FeedingSpeed);
  ReefAngel.RF.WaterChangeSpeed=InternalMemory.read(Mem_B_WCSpeed);
 
  vtMode=InternalMemory.RFMode_read();
  vtSpeed=InternalMemory.RFSpeed_read();
  vtDuration=InternalMemory.RFDuration_read();

  if ((now()-t > ntmDelay && now()-t < ntmTime+ntmDelay) && feedingRF) {
    // Post feeding mode
    vtMode=Smart_NTM;
    vtSpeed=InternalMemory.read(Mem_B_NTMSpeed);
    vtDuration=InternalMemory.read(Mem_B_NTMDuration);
  } else if (!sun.IsDaytime() && nightRF) {
    vtMode=Night;
    vtSpeed=InternalMemory.read(Mem_B_NightSpeed);
    vtDuration=InternalMemory.read(Mem_B_NightDuration);
  } else {
    if (vtMode!=Night && ReefAngel.RF.Mode==Night)
      ReefAngel.RF.SetMode(Night_Stop,0,0);
  }

  if (ReefAngel.DisplayedMenu==FEEDING_MODE) {
    t=now(); // Run post feeding mode when this counter stops
  } else if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE) {
    // Not needed anymore.
    // ReefAngel.RF.SetMode(Constant,25,0);
  } else {
    if ((vtMode==Smart_NTM) || (vtMode==ShortPulse)) vtDuration=InternalMemory.read(Mem_B_NTMDuration);
    (vtMode==Custom) ? RFCustom() : ReefAngel.RF.SetMode(vtMode,vtSpeed,vtDuration);
  }
}

void RFCustom() {
  static boolean changeMode;
  byte rcSpeed, rcSpeedAS;

  // Define new modes
  const int BHazard=15;
  const int RA_ReefCrest=16;
  const int RA_Lagoon=17;
  const int RA_TidalSwell=18;
  const int RA_Smart_NTM=19;
  const int RA_ShortPulse=20;
  const int RA_LongPulse=21;
 
  byte tideSpeed=tide.CalcTide();
  byte tideMin=InternalMemory.read(Mem_B_TideMin);
  byte tideMax=InternalMemory.read(Mem_B_TideMax);
  byte tideMode=InternalMemory.read(Mem_B_TideMode);
  float pumpOffset=(float) InternalMemory.read(Mem_B_PumpOffset)/100;

  byte RandomModes[]={ ReefCrest, TidalSwell, Smart_NTM, Lagoon, ShortPulse, LongPulse, BHazard, Else, Sine, Constant };

//  if (now()%SECS_PER_DAY!=0 && InternalMemory.read(Mem_B_RandomMode)) changeMode=true;
//  if (now()%SECS_PER_DAY==0 && changeMode) {

  if (now()%(6*SECS_PER_HOUR)!=10 && InternalMemory.read(Mem_B_RandomMode)) changeMode=true;
  if (now()%(6*SECS_PER_HOUR)==10 && changeMode) {
    tideMode=random(100)%sizeof(RandomModes);
    InternalMemory.write(Mem_B_TideMode,tideMode);
    changeMode=false;
  }
 
  // Choose another random mode if triggered
  if (InternalMemory.read(Mem_B_ForceRandomTide)) {
    tideMode=random(100)%sizeof(RandomModes);
    InternalMemory.write(Mem_B_TideMode,tideMode);
    InternalMemory.write(Mem_B_ForceRandomTide,false);
  }
 
  ReefAngel.CustomVar[Var_TideMode]=tideMode+1;

  switch (RandomModes[tideMode]) {
    case ReefCrest: {
      ReefAngel.RF.SetMode(ReefCrest,tideSpeed,vtDuration);
      return;
      break;
    }
    case Lagoon: {
      ReefAngel.RF.SetMode(Lagoon,tideSpeed,vtDuration);
      return;
      break;
    }
    case TidalSwell: {
      ReefAngel.RF.SetMode(TidalSwell,tideSpeed,vtDuration);
      return;
      break;
    }
    case Smart_NTM: {
      ReefAngel.RF.SetMode(Smart_NTM,tideSpeed,vtDuration);
      return;
      break;
    }
    case ShortPulse: {
      ReefAngel.RF.SetMode(ShortPulse,tideSpeed,vtDuration);
      return;
      break;
    }
    case LongPulse: {
      ReefAngel.RF.SetMode(LongPulse,tideSpeed,vtDuration);
      return;
      break;
    }
    case RA_ReefCrest: {
      rcSpeed=ReefCrestMode(tideSpeed,vtDuration*2,true);
      rcSpeedAS=ReefCrestMode(tideSpeed,vtDuration*2,false);
      break;
    }
    case RA_Lagoon: {
      rcSpeed=ReefCrestMode(tideSpeed,vtDuration,true);
      rcSpeedAS=ReefCrestMode(tideSpeed,vtDuration,false);
      break;
    }
    case RA_TidalSwell: {
      rcSpeed=TidalSwellMode(tideSpeed,true);
      rcSpeedAS=TidalSwellMode(tideSpeed,false);
      break;
    }
    case RA_Smart_NTM: {
      rcSpeed=NutrientTransportMode(0,tideSpeed,vtDuration*50,true);
      rcSpeedAS=NutrientTransportMode(0,tideSpeed,vtDuration*50,false);
      break;
    }
    case RA_ShortPulse: {
      rcSpeed=ShortPulseMode(0,tideSpeed,vtDuration*50,true);
      rcSpeedAS=ShortPulseMode(0,tideSpeed,vtDuration*50,false);
      break;
    }
    case RA_LongPulse: {
      rcSpeed=LongPulseMode(0,tideSpeed,vtDuration,true);
      rcSpeedAS=LongPulseMode(0,tideSpeed,vtDuration,false);
      break;
    }   
    case Else: {
      rcSpeed=ElseMode(tideSpeed,vtDuration*2,true);
      rcSpeedAS=ElseMode(tideSpeed,vtDuration*2,false);
      break;
    }   
    case BHazard: {
      rcSpeed=millis()%1200>800?tideSpeed:0;
      rcSpeedAS=millis()%1200<400?0:tideSpeed;
      break;
    }
    case Sine: {
      rcSpeed=SineMode(tideSpeed-tideMin,tideSpeed+tideMin,vtDuration*100,true);
      rcSpeedAS=SineMode(tideSpeed-tideMin,tideSpeed+tideMin,vtDuration*100,false);
      break;
    }
    default: {
      rcSpeed=tideSpeed;
      rcSpeedAS=tideSpeed; 
      pumpOffset=(float) InternalMemory.read(Mem_B_GyreOffset)/100;
    }
  }

  ReefAngel.RF.SetMode(Custom,rcSpeedAS*pumpOffset,tide.isOutgoing());
  ReefAngel.RF.SetMode(Custom,rcSpeed,tide.isIncoming());
}

void NextRFMode() {
  vtMode++;
 
  if (vtMode > 12) {
    vtMode=0;
    vtSpeed=50; // Constant
  } else if (vtMode == 1) {
    vtSpeed=40; // Lagoon
  } else if (vtMode == 2) {
    vtSpeed=45; // Reef Crest
  } else if (vtMode == 3) { 
    vtSpeed=55; vtDuration=10; // Short Pulse
  } else if (vtMode == 4) {
    vtSpeed=55; vtDuration=20; // Long Pulse
  } else if (vtMode == 5) {
    vtSpeed=InternalMemory.read(Mem_B_NTMSpeed);
    vtDuration=InternalMemory.read(Mem_B_NTMDuration); // Smart_NTM
  } else if (vtMode == 6) {
    vtSpeed=50; vtDuration=10; // Smart_TSM
  } else if (vtMode == 7) {
    vtSpeed=InternalMemory.read(Mem_B_NightSpeed);
    vtDuration=InternalMemory.read(Mem_B_NightDuration);
    vtMode=9; // Night
  } else if (vtMode == 10) {
    vtSpeed=65; vtDuration=5; // Storm
  } else if (vtMode == 11) {
    vtSpeed=45; vtDuration=10; // Custom
  } 

  if (vtMode!=InternalMemory.RFMode_read())
    InternalMemory.RFMode_write(vtMode);
  if (vtSpeed!=InternalMemory.RFSpeed_read())
    InternalMemory.RFSpeed_write(vtSpeed);
  if (vtDuration!=InternalMemory.RFDuration_read())
    InternalMemory.RFDuration_write(vtDuration);
}

// Calculate evaportation rate
void CheckATO() {
  byte numHours, index, level, delta;
  float duration;
  const int logHours=12;
  static float rate, logLevel[logHours];
  static boolean rateSaved, rateInit, refillActive;
   
  numHours=(now()%(SECS_PER_HOUR*logHours))/SECS_PER_HOUR;
  level=ReefAngel.WaterLevel.GetLevel(1);
     
  // Initialize the array based on last rate
  // Wait a little to make sure WL reading properly. Or we're refilling.
  if (now()-LastStart>1 && !rateInit) {
    rateInit=true;
    index=numHours;
    rate=InternalMemory.read(Mem_B_LogATO);
    for (byte i=0;i<logHours;i++) {
      logLevel[index]=level+(i*(rate/24.0));
      //Serial.print(i);
      //Serial.print(": ");
      //Serial.print(index);
      //Serial.print(": ");
      //Serial.println(logLevel[index]);
      index>0?index--:index=11;
    }
  }
     
  if(minute()==59 && rateSaved==false) {
    InternalMemory.write(Mem_B_LogATO, rate);
    logLevel[numHours]=level;   
    rateSaved=true;
  } else {
    rateSaved=false;
  }
 
  ReefAngel.CustomVar[Var_LogATO]=rate;
  // if(now()%30==0) Serial.println(rate);
}

void RefugiumLight() {
  int runtime=2*SECS_PER_HOUR;
  static boolean trigger=false;
  static time_t t;
 
  // Refugium Light Turned on
  if (ReefAngel.Relay.isMaskOn(Refugium) && trigger==false) {
    t=now();
    trigger=true;
  } 

  if ((now()-t > runtime) && trigger==true) {
    ReefAngel.Relay.Auto(Refugium);
    trigger=false;
  } 
}

// Menu Code
void MenuEntry1() {
  // Toggle refugium light between on/auto.
  ReefAngel.Relay.Override(Refugium, ReefAngel.Relay.Status(Refugium)+1);
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}
void MenuEntry2() {
  ReefAngel.FeedingModeStart();
}
void MenuEntry3() {
  ReefAngel.WaterChangeModeStart();
}
void MenuEntry4() {
  NextRFMode(); 
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}
void MenuEntry5() {
  ReefAngel.ATOClear();
  ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry6() {
  ReefAngel.OverheatClear();
  ReefAngel.DisplayMenuEntry("Clear Overheat");
}
void MenuEntry7() {
  ReefAngel.SetupCalibratePH();
}
void MenuEntry8() {
  ReefAngel.SetupCalibrateWaterLevel();
}
void MenuEntry9() {
  ReefAngel.SetupDateTime();
}

// Custom Main Screen
void DrawCustomMain() {
  const int NumScreens=3;
  static boolean drawGraph=true;
 
  // Main Header
  // ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 35, 2,"Lee's Reef");
  ReefAngel.LCD.DrawDate(5,2);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, 11, 128, 11);

  // Param Header
  DrawParams(5,14);
 
  switch (ScreenID) {
    case 0:
    {
      if (drawGraph) { ReefAngel.LCD.DrawGraph(5,40); drawGraph=false; }
      break;
    }
    case 1: { DrawStatus(5,40); break; }
    case 2: { DrawSunMoon(5,40); break; }
     }
 
  // Draw Relay
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 103, TempRelay);
 
  // Date+Time
  // ReefAngel.LCD.DrawDate(5,122);
 
  if (ReefAngel.Joystick.IsLeft()) {
    ReefAngel.ClearScreen(DefaultBGColor);
    ScreenID--; drawGraph=true;
  }
  if (ReefAngel.Joystick.IsRight()) {
    ReefAngel.ClearScreen(DefaultBGColor);
    ScreenID++; drawGraph=true;
  }
  if (ScreenID<0) ScreenID=NumScreens-1;
  if (ScreenID>=NumScreens) ScreenID=0;
 
}

void DrawCustomGraph() {
  if (ScreenID==0)
    ReefAngel.LCD.DrawGraph(5, 40);
}

void DrawParams(int x, int y) {
  char buf[16];

  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x+5,y,"Temp:");
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x+80, y, "PH:");
  // Temp and PH
  y+=2;
  ConvertNumToString(buf, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawText(T2TempColor, DefaultBGColor, x+45, y, buf);
  y+=6;
  ConvertNumToString(buf, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T1TempColor, DefaultBGColor, x+5, y, buf, Num8x16);
  ConvertNumToString(buf, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+80, y, buf, Num8x16);
 // y+=5;
 // ConvertNumToString(buf, ReefAngel.Params.Temp[T3_PROBE], 10);
 // ReefAngel.LCD.DrawText(T3TempColor, DefaultBGColor, x+45, y, buf);
}

void DrawStatus(int x, int y) {
  int t=x;
 
  ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,15,y,"High",Font8x16);
  ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,85,y,"Low",Font8x16);
 
  if (ReefAngel.HighATO.IsActive()) {
    ReefAngel.LCD.FillCircle(55,y+3,5,COLOR_GREEN);
  } else {
    ReefAngel.LCD.FillCircle(55,y+3,5,COLOR_RED);
  }
 
  if (ReefAngel.LowATO.IsActive()) {
    ReefAngel.LCD.FillCircle(70,y+3,5,COLOR_GREEN);
  } else {
    ReefAngel.LCD.FillCircle(70,y+3,5,COLOR_RED);
  }
  y+=12;
 
  // Display Water level
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"AT0 Level:"); x+=65;
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.WaterLevel.GetLevel(1),DPColor,x,y,1);
  x+=5*(intlength(ReefAngel.WaterLevel.GetLevel(1))+1);
  ReefAngel.LCD.DrawText(DPColor, DefaultBGColor, x, y, "%");
  y+=12; x=t;
 
  // Vortech Mode
  ReefAngel.LCD.DrawText(0,255,x,y,"RF:"); x+=20;
  ReefAngel.LCD.Clear(DefaultBGColor,x,y,t+(128-t),y+8);
  if (vtMode == 0) ReefAngel.LCD.DrawLargeText(COLOR_GREEN,255,x,y,"Constant");
  else if (vtMode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,x,y,"Lagoon");
  else if (vtMode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,x,y,"Reef Crest");
  else if (vtMode == 3) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,x,y,"Short Pulse");
  else if (vtMode == 4) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,x,y,"Long Pulse");
  else if (vtMode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,x,y,"Smart NTM");
  else if (vtMode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,x,y,"Tidal Swell");
  else if (vtMode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,x,y,"Night");
  else if (vtMode == 10) ReefAngel.LCD.DrawLargeText(COLOR_BLUE,0,x,y,"Storm");
  else if (vtMode == 11) ReefAngel.LCD.DrawLargeText(COLOR_BLUE,255,x,y,"Custom");
  y+=10; x=t;
 
  ReefAngel.LCD.DrawText(0,255,x,y,"RF Speed:"); x+=60;
  ReefAngel.LCD.Clear(DefaultBGColor,x,y,128,y+8);
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,x,y,vtSpeed); x+=15;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,x,y,"/"); x+=10;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,x,y,vtDuration);
  y+=10; x=t;
 
}

void DrawSunMoon(int x, int y) {
  char buf[16];
  int t=x;

  y+=2;
  /// Display Sunrise / Sunset
  sprintf(buf, "%02d:%02d", sun.GetRiseHour(), sun.GetRiseMinute());
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"Rise:"); x+=31;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,buf);
  sprintf(buf, "%02d:%02d", sun.GetSetHour(), sun.GetSetMinute()); x+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"Set:"); x+=25;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,buf);
  y+=15; x=t;
 
  /// Display Moonrise / Moonset
  sprintf(buf, "%02d:%02d", Moon.riseH, Moon.riseM);
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MR:"); x+=21;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,buf);
  sprintf(buf, "%02d:%02d", Moon.setH, Moon.setM); x+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MS:"); x+=21;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,buf); x+=36;
  if (Moon.isUp) ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,"@");
    else ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,"_");
  y+=10; x=t;
 
  // MoonPhase
  ReefAngel.LCD.DrawText(0,255,x,y,"Moon:");
  ReefAngel.LCD.Clear(DefaultBGColor,x+32,y,128,y+8);
  ReefAngel.LCD.DrawText(COLOR_MAGENTA,255,x+32,y,MoonPhaseLabel());
  y+=10; x=t;
}
User avatar
Posts: 5349
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Sat Dec 24, 2016 6:42 pm
I would have to compare what you've changed in the code. I've found the init function well if you try to trigger that...and you need manual steps to try and trigger it...so try setting all the memory variables or at least verifying them before going further. When in doubt we can replace memory calls with static variables. Start with one function at a time that we can work on. Give me your current if you can describe the changes and then also the value in your memory locations.

Posts: 7
Joined: Sat Mar 29, 2014 4:05 pm
PostPosted: Sun Dec 25, 2016 7:52 pm
I have been going through and replacing the memory calls with static variables, and I think that has fixed a lot of it.

I still have an expansion Box 1 showing up on the portal, and I'm not sure the Evaporation code is working, since it seems to always display 0, but definitely making progress.

Thanks!
User avatar
Posts: 5349
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Sun Dec 25, 2016 9:24 pm
I'm not sure my latest evaporation code is published. I made a huge amount of improvement on it. Are you using it the same way to measure your ato reservoir usage? I have a WL sensor in there and so basing it off that history.

Posts: 7
Joined: Sat Mar 29, 2014 4:05 pm
PostPosted: Mon Dec 26, 2016 3:12 pm
Yes, I want to calculate my tanks evaporation rate by measuring the WL in my ATO reservoir. The code of yours I have been using is...

Code: Select all
int Mem_B_LogATO=0;

// Calculate evaportation rate
void CheckATO() {
  byte numHours, index, level, delta;
  float duration;
  const int logHours=12;
  static float rate, logLevel[logHours];
  static boolean rateSaved, rateInit, refillActive;
   
  numHours=(now()%(SECS_PER_HOUR*logHours))/SECS_PER_HOUR;
  level=ReefAngel.WaterLevel.GetLevel(1);
     
  // Initialize the array based on last rate
  // Wait a little to make sure WL reading properly. Or we're refilling.
  if (now()-LastStart>1 && !rateInit) {
    rateInit=true;
    index=numHours;
    rate=Mem_B_LogATO;
    for (byte i=0;i<logHours;i++) {
      logLevel[index]=level+(i*(rate/24.0));
      //Serial.print(i);
      //Serial.print(": ");
      //Serial.print(index);
      //Serial.print(": ");
      //Serial.println(logLevel[index]);
      index>0?index--:index=11;
    }
  }
     
  if(minute()==59 && rateSaved==false) {
    rate=Mem_B_LogATO;
    logLevel[numHours]=level;   
    rateSaved=true;
  } else {
    rateSaved=false;
  }


I just get 0.

Return to How do I code ...

Who is online

Users browsing this forum: No registered users and 1 guest