Lee's Feature Complete PDE

Share you PDE file with our community
Post Reply
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Added in the PWMSlopeOvernight() function so that now my moonlights will dim off and then dim back on (Well actually they are going the opposite way, but "overnight" so it just seems that way :D )

Also simplified my isNight check using the new GetSunRise() and GetSunSet() functions added to the SunLocation class. Much easier now since we can compare to now().

Finally, added a function (RefugiumLights()) similar to MoonLights() that will respect the ActinicOffset() and turn on my refugium light opposite my actinics based on the StandardLights memory variables.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Lee's Feature Complete PDE

Post by rimai »

Cool!!
Roberto.
TanksNStuff
Posts: 188
Joined: Fri Dec 30, 2011 6:57 am

Re: Lee's Feature Complete PDE

Post by TanksNStuff »

Lee, was just reviewing your code from your 2nd post in this thread. I like a lot of the features you included and I will likely try to adopt a few of them for my custom code.

However, I was curious/confused as to why you put all this at the end when typically the custom menu and display stuff is usually at the beginning:

Code: Select all

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

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

// Vortech Helper functions
void setRFmode(int mode, int speed, int duration) {

  // Check if mode has changed
  if (mode!=vtMode) {  
    vtPrevMode=vtMode;
    vtMode=mode; 
  
    if (mode!=InternalMemory.RFMode_read()) { 
      InternalMemory.RFMode_write(mode); 
    }
    
    // Fix for coming out of night mode
    if (vtPrevMode==Night) {
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Feeding_Stop,0,0);
      ReefAngel.RF.UseMemory=true;
    }
    
    // If it's at night or we are setting NTM, do this only temporarily
    if ( (isNight && vtMode != Night) || vtMode==Smart_NTM) {
      setRFtimer(60);
    }
  } 

  // Check if speed has changed
  if (speed!=vtSpeed) {  
    vtPrevSpeed=vtSpeed;
    vtSpeed=speed;
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    } 
  }

  // Check if duration has changed
  if (duration!=vtDuration) {  
    vtPrevDuration=vtDuration;
    vtDuration=duration; 
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    }
  }
}
void setRFmode() {
  setRFmode(InternalMemory.RFMode_read(), InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
}
void setRFtimer(int minutes) {
  ReefAngel.Timer[1].SetInterval(minutes*60);
  ReefAngel.Timer[1].Start();
  vtOverride=true;
}

byte PWMSlopeOvernight(byte startHour, byte startMinute, byte endHour, byte
endMinute, byte startPWM, byte endPWM, byte Duration, byte oldValue)
{
  
  unsigned long Start = previousMidnight(now())+((unsigned long)NumMins(startHour, startMinute)*60);
  if (hour()<startHour) Start-=86400;
  unsigned long StartD = Start + (Duration*60);
  unsigned long End = nextMidnight(now())+((unsigned long)NumMins(endHour, endMinute)*60);
  if (hour()<startHour) End-=86400;
  unsigned long StopD = End - (Duration*60);
  if ( now() >= Start && now() <= StartD )
    return constrain(map(now(), Start, StartD, startPWM, endPWM),startPWM,
    endPWM);
  else if ( now() >= StopD && now() <= End )
  {
    byte v = constrain(map(now(), StopD, End, startPWM, endPWM),startPWM,
    endPWM);
    return endPWM-v+startPWM;
  }
  else if ( now() > StartD && now() < StopD )
    return endPWM;

  // lastly return the existing value
  return oldValue;
}

// Similar to MoonLights() but adding in ActinicOffset
void RefugiumLights(byte Relay)
{
  int MinuteOffset=InternalMemory.ActinicOffset_read();
  int onTime=NumMins(InternalMemory.StdLightsOffHour_read(),InternalMemory.StdLightsOffMinute_read())+MinuteOffset;
  int offTime=NumMins(InternalMemory.StdLightsOnHour_read(),InternalMemory.StdLightsOnMinute_read())-MinuteOffset;
  
  ReefAngel.StandardLights(Relay,onTime/60,onTime%60,offTime/60,offTime%60);
}

// Menu Code
void MenuEntry1() {
  ReefAngel.FeedingModeStart();
}
void MenuEntry2() {
  ReefAngel.WaterChangeModeStart();
}
void MenuEntry3() {
  byte mode,speed,duration;
  byte prev_mode,prev_speed,prev_dur;
  
  mode=vtMode;
  mode++;
  
  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  
  if (mode > 9) { 
    mode=0; 
    speed=50; duration=0; // Constant
  } else if (mode == 1) { 
    speed=40; duration=0; // Lagoon
  } else if (mode == 2) { 
    speed=45; duration=0; // Reef Crest
  } else if (mode == 3) {  
    speed=55; duration=10; // Short Pulse
  } else if (mode == 4) {
    speed=55; duration=20; // Long Pulse
  } else if (mode == 6) {
    speed=50; duration=10; // Smart_TSM
  } else if (mode == 5) {
    speed=vtNTMSpeed; duration=vtNTMDuration; // Smart_NTM
  } else if (mode == 7) {
    speed=vtNightSpeed; duration=vtNightDuration; // Night
    mode=9; 
  }  

  // Backup the previous modes. We don't want Night to become default...
  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  setRFmode(mode,speed,duration);
  
  // If it's night time, don't overwrite the default daytime mode when using the menu
  if (!isNight) {
    vtPrevMode=prev_mode; vtPrevSpeed=prev_speed; vtPrevDuration=prev_dur;
  }
  
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry4() {
  // Toggle the refugium light if we choose this menu entry.
  // Behavior is opposite for night vs day.
  
  if (isNight) { // Turn off the Refugium light
    if (bitRead(ReefAngel.Relay.RelayMaskOff,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    }
  } else { // Turn on the Refugium light
    if (bitRead(ReefAngel.Relay.RelayMaskOn,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    }
  }
  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();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8() {
  ReefAngel.SetupCalibrateWaterLevel();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry9() {
  ReefAngel.SetupDateTime();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}

// Custom Main Screen
void DrawCustomMain() {
  char buf[16];
  byte x = 5;
  byte y = 2;
  byte t;

  // Main Header
  // ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 35, y,"Lee's Reef");
  // Had no room for this anymore :(
  
  // Date+Time
  ReefAngel.LCD.DrawDate(x+1, y);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, y+9, 128, y+9);
  
  // Param Header
  y+=12; 
  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);
  pingSerial();
    
  /// Display Sunrise / Sunset (to be calculated later...)
  y+=12; t=x;
  sprintf(buf, "%02d:%02d", sl.GetRiseHour(), sl.GetRiseMinute());
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Rise:"); t+=31;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf); 
  sprintf(buf, "%02d:%02d", sl.GetSetHour(), sl.GetSetMinute()); t+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Set:"); t+=25;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf);
  pingSerial();

  // MoonPhase
  y+=10; 
  ReefAngel.LCD.DrawText(0,255,x,y,"Moon:");
  ReefAngel.LCD.Clear(DefaultBGColor,x+32,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_MAGENTA,255,x+32,y,MoonPhaseLabel());
  pingSerial();
  
  // MoonLight %
  y+=10;
  t = intlength(ReefAngel.PWM.GetDaylightValue()) + 1;  t *= 5;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MoonLights:"); 
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+68, y, 1);
  ReefAngel.LCD.DrawText(DPColor, DefaultBGColor, x+68+t, y, "%");
  pingSerial();

  // Display Water level
  y+=10; t=x;
  ConvertNumToString(buf, ReefAngel.WaterLevel.GetLevel(), 1);
  strcat(buf,"  ");
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"AT0 Level:"); t+=60;
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,t,y,buf);

  // Vortech Mode
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF:"); t+=20;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  if (vtMode == 0) ReefAngel.LCD.DrawLargeText(COLOR_GREEN,255,t,y,"Constant");
  else if(vtMode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Lagoon");
  else if (vtMode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Reef Crest");
  else if (vtMode == 3) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Short Pulse");
  else if (vtMode == 4) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Long Pulse");
  else if (vtMode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Smart NTM");
  else if (vtMode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Tidal Swell");
  else if (vtMode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,t,y,"Night");
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF Speed:"); t+=60;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFSpeed_read()); t+=15;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,"/"); t+=10;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFDuration_read());
  pingSerial();
  
  // Display Water level
  y+=10; t=x;
  if (acclDay > 0) {
    ConvertNumToString(buf, acclDay, 1);
    strcat(buf,"  ");
    ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Acclimation Day:"); t+=100;
    ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,t,y,buf);
  } else {
    ReefAngel.LCD.Clear(DefaultBGColor,x,y,x+(128-x),y+8);
  }
  
  // Relays
  y+=10; t=x+7;
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(t, y, TempRelay);
  pingSerial();
  y+=12;
  TempRelay = ReefAngel.Relay.RelayDataE[0];
  TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawOutletBox(t, y, TempRelay);
  pingSerial();
}

void DrawCustomGraph() {
}

Was it necessary to put it there for some reason? You didn't follow the " // This should always be the last line
" comments.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

TanksNStuff wrote:

Code: Select all

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

  // This should always be the last line
  ReefAngel.Portal("lnevo");
  ReefAngel.ShowInterface();
}
Was it necessary to put it there for some reason? You didn't follow the " // This should always be the last line
" comments.
If you look at the function loop() I did follow the " // This should always be the last line" comment. That comment means those two calls should be the last things that are executed by the loop() function.

The reason the rest of the stuff is below it was just a means to make it easier for me to edit and update the code. I was tried of scrolling through all the menu code and helper functions. This way, after my variable declarations and such, I would just have setup() followed by loop() where most of my code is located. It's really just a matter of preference :)
TanksNStuff
Posts: 188
Joined: Fri Dec 30, 2011 6:57 am

Re: Lee's Feature Complete PDE

Post by TanksNStuff »

Oh, OK. Making it more convenient is a good excuse. I just thought that all of that had to be up top. I didn't realize it would still work if it was after the loop.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

A little bit of cleanup today. I removed the reliance on my isNight boolean variable.... I didn't think it was really needed.

In doing so, I streamlined my toggle for the Refugium light from the menu.

Code: Select all

  if (bitRead(ReefAngel.Relay.RelayData, Refugium-1)) { // If relay is on.
    // Toggle MaskOff for the light
    bitWrite(ReefAngel.Relay.RelayMaskOff, Refugium-1, 1-bitRead(ReefAngel.Relay.RelayMaskOff, Refugium-1));
  } else { 
    // Toggle the MaskOn for the light
    bitWrite(ReefAngel.Relay.RelayMaskOn, Refugium-1, 1-bitRead(ReefAngel.Relay.RelayMaskOn, Refugium-1));
  }
I also streamlined some of my RF menu functions, so if I change from the menu, it's always a temporary change. I only set the timer when I go to Smart_NTM now or if done from the menu. Changing the memory setting is now the only way to change the default RF mode. If it's changed at night, it should only change momentarily (unless Smart_NTM which will trigger the timer..)

I also came up with a neat trick to have something run at a particular time of day. Instead of doing comparing now() to hour(), minute(), and second()...

Code: Select all

  if (now()%SECS_PER_DAY==54000) { // 3pm.
    setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
  }
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Lee's Feature Complete PDE

Post by binder »

TanksNStuff wrote:Oh, OK. Making it more convenient is a good excuse. I just thought that all of that had to be up top. I didn't realize it would still work if it was after the loop.
Technically it shouldn't work at the end of the file unless you define the functions up top before they are used (standard C/C++ syntax). However, arduino does things a little different because what we write in our PDE/INO files is actually included into a "base" main file that runs our setup() function first and then falls into an infinite loop calling the loop() function. Plus the arduino preprocessor appears to scan and generate other files needed to make things work. So the functions at the bottom of our file are already defined before they are used.
Yeah, it's a little confusing and it took me a while to understand what it was doing too. I looked at this when I was considering adding in compilation to my old RAGen program.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Hey it works... :) I moved around some of the code actually because my helper functions were starting to take more room and getting in the way between my loop() and Menu functions which I edit more often.

Also, played around with different GPS coordinates. Ended up off the coast of Chile to get a smaller timezone offset, but maintaining the day length and season cycle of GBR. I may switch in the spring to North of the equator to get in sync with our Winter/Summer day length schedule.. we'll see how this shapes up...
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

So this week I did quite a bit of work on my code. I hacked up a routine to automate my water change and finished up the Tide class code. I had some time to test the water change code this weekend and it did take some tweaking because my float switch I'm trying to use is upside down for the SingleATO function to work properly. Currently I hacked the SingleATO function :)

Anyway, when I get my skimmate collector, I will rewire and re-orient my float switches. I was going to put both switches in parallel but since I need the float switch in active mode to trigger the ATO functions, I'm going to put them in series and have them both activated. If either goes in-active it will break the circuit and disable my return pump. When in water change mode though, it will turn my WC pump into an ATO pump :)

I also finished up the design for my Night mode since with my Tide program, I didn't want to interrupt the high tide/low tide functionality. I used the PWMSlope to create a transition between Night Speed and my normal speed. The value will be used to adjust the Tide class speed.

Anyway, code will be posted up soon. Looking forward to testing the tide stuff and getting to do more frequent water changes. I'm really pleased with my method for water changing now, just need to fine tune the plumbing and the process. I really like being able to rinse new media while simultaneously doing a water change :)
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Ok, I'm archiving my last version before I moved forward with my non-memory based RF code if anyone needs to reference it. The new version still uses memory but since the speed is going to change constantly based on my new Custom mode, I didn't want to keep reading/writing from memory. So here you go if anyone needs the reference for some reason.

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 <RF.h>
#include <ReefAngel.h>
#include <SunLocation.h>
#include <WaterLevel.h>

#define NUMBERS_8x16

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

// Custom Menu Code
#include <avr/pgmspace.h>
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "Vortech Mode";
prog_char menu4_label[] PROGMEM = "Refugium Light";
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
};

// Vortech Defaults
byte vtPrevMode=0;
byte vtPrevSpeed=0;
byte vtPrevDuration=0;
// Default Mode
byte vtMode=Random2;
byte vtSpeed=45;
byte vtDuration=5;
// NTM mode
byte vtNTMSpeed=65;
byte vtNTMDuration=5;
// Night Mode
byte vtNightSpeed=20;
byte vtNightDuration=10;
TimerClass rfTimer;

boolean isFeeding=false;
boolean feedDelay=false;
boolean vtOverride=false;
boolean floatHigh=true;
boolean powerOutage=true;

SunLocation sl;
byte acclDay=0;
byte vacationMode=0;

byte wcReady=0;
int wcFillTime=0;
TimerClass wcTimer;

//Define Custom Memory Location
#define Mem_B_RefillATO   100
#define Mem_B_Vacation    102
#define Mem_B_AcclDay     103
#define Mem_B_WaterChange 105
#define Mem_I_WCFillTime  106

#define Var_HighATO    0
#define Var_Power      1
#define Var_Vacation   2
#define Var_AcclDay    3

//Define Relay Ports by Name
#define Return             1
#define Skimmer            2
#define WhiteLEDs          3
#define BlueLEDs           4
#define Extension          5
#define Heater             6
#define Refugium           7
#define Reactor            8

#define Unused1            Box1_Port1
#define Unused2            Box1_Port2
#define Vortech1           Box1_Port3
#define Vortech2           Box1_Port4
#define VortechUPS         Box1_Port5
#define Unused3            Box1_Port6
#define DPump1             Box1_Port7
#define DPump2             Box1_Port8

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

// Setup on controller startup/reset
void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Initialize Menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port8Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port2Bit | Port8Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port3Bit | Port4Bit ;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port3Bit | Port4Bit | Port6Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    
    // Ports that default on
    ReefAngel.Relay.On(Return);
    ReefAngel.Relay.On(Vortech1);
    ReefAngel.Relay.On(Vortech2);
    ReefAngel.Relay.On(VortechUPS);
    // Ports that default off
    ReefAngel.Relay.Off(Extension);
    ReefAngel.Relay.Off(Unused1);
    ReefAngel.Relay.Off(Unused2);
    ReefAngel.Relay.Off(Unused3);
    
    ////// Place additional initialization code below here
    // sl.Init(-21.08931,-147.699722); // Default - GBR
    // sl.Init(21.30891,-147.699722); // Near Honolulu, HI
    sl.Init(-21.08931, -73.528383); // Off the coast of Chile
    
    // What was our previous modes before we restarted?
    vtPrevMode=InternalMemory.RFMode_read();
    vtPrevSpeed=InternalMemory.RFSpeed_read();
    vtPrevDuration=InternalMemory.RFDuration_read();
    
    // Dummy CustomVar to activate portal feature
    ReefAngel.CustomVar[7]=255;
    
    ////// Place additional initialization code above here
}

void loop()
{
  // Default port modes. Use Memory settings for external control
  ReefAngel.StandardHeater(Heater);
  //ReefAngel.DosingPumpRepeat1(DPump1);
  //ReefAngel.DosingPumpRepeat2(DPump2);
  ReefAngel.StandardLights(WhiteLEDs);
  ReefAngel.ActinicLights(BlueLEDs);
    
  ////// Place your custom code below here

  RefugiumLights(Refugium);
  
  // Moonlights on from 5:00am-3:00am so 3am-5am is complete darkness 
  ReefAngel.PWM.SetDaylight(PWMSlopeOvernight(5,0,3,0,0,MoonPhase(),30,0));
  ReefAngel.PWM.SetActinic(PWMSlopeOvernight(5,0,3,0,0,MoonPhase(),30,0));
  
  // See if power is back on so DelayedOn ports will reset.
  if (powerOutage && ReefAngel.Relay.IsRelayPresent(EXP1_RELAY))
  {
    powerOutage=false;
    LastStart=now();
    ReefAngel.CustomVar[Var_Power]=0;
  }
  ReefAngel.Relay.DelayedOn(Skimmer); 
  ReefAngel.Relay.DelayedOn(Reactor,1); 

  // See if we are acclimating corals and decrement the countdown each night
  static boolean acclCounterReady=false;
  if (now()%SECS_PER_DAY!=0) acclCounterReady=true;
  
  acclDay=InternalMemory.read(Mem_B_AcclDay);
  ReefAngel.CustomVar[Var_AcclDay]=acclDay;
  if (acclDay > 0) { 
    if (acclCounterReady && now()%SECS_PER_DAY==0) {
      acclDay--;
      acclCounterReady=false;
      InternalMemory.write(Mem_B_AcclDay,acclDay);
    }
  }  
  
  // -9 hour difference for time zone. 472/506 seconds were calculation corrections
  // The acclDay will adjust the sunrise/sunset if we are adjusting for new coral
  // sl.SetOffset(14,472+(acclDay*240),14,506-(acclDay*120)); // GBR
  // sl.SetOffset(-6,472(acclDay*240),-6,506-(acclDay*120)); // Honolulu, HI
  sl.SetOffset(-1,(acclDay*240),-1,(-acclDay*120)); // Off the coast of Chile
  
  // Calculate the new Sunrise / Sunset based on our GPS coordinates
  sl.CheckAndUpdate();

  if ( (now() >= sl.GetSunRise()) && (now() <= (sl.GetSunSet()-30)) ) // It's Daytime
  {
    // Turn off MoonLights
    ReefAngel.PWM.SetDaylight(0);
    ReefAngel.PWM.SetActinic(0);

    // Come out of Night mode.
    if (vtOverride==false && vtMode==Night) {
      setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
    }
  } else { 
    // Set Vortech's to Night mode.
    if (vtOverride==false && isFeeding==false) {
      setRFmode(Night,vtNightSpeed,vtNightDuration);
    }
  }   
 
  // Some Tidal Swell 
  if (now()%SECS_PER_DAY==43200) { // 12pm.
    setRFmode(Smart_TSM,50,10);
    setRFtimer(60);
  }  
  
  // Some Short Pulse action
  if (now()%SECS_PER_DAY==50400) { // 2pm.
    setRFmode(ShortPulse,55,10);
    setRFtimer(30);
  }  
  
  // A little extra Smart_NTM never hurt anyone
  if (now()%SECS_PER_DAY==54000) { // 3pm.
    setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
  }
    
  // Some lagoon action
  if (now()%SECS_PER_DAY==59400) { // 4:30pm.
    setRFmode(Lagoon,40,0);
    setRFtimer(30);
  }
  
  // Some Long Pulse action
  if (now()%SECS_PER_DAY==64800) { // 6pm
    setRFmode(LongPulse,55,20);
    setRFtimer(30);
  }

  // Enable Feeding Mode flag
  if (ReefAngel.DisplayedMenu==FEEDING_MODE) isFeeding=true;
  // Turn on Refugium light during feeding anwater change mode
  if (ReefAngel.DisplayedMenu==FEEDING_MODE || ReefAngel.DisplayedMenu==WATERCHANGE_MODE) ReefAngel.Relay.On(Refugium);
  // Enable ATOHigh flag on purpose during feed/water change mode so we don't get alerts.
  if (ReefAngel.DisplayedMenu==FEEDING_MODE || ReefAngel.DisplayedMenu==WATERCHANGE_MODE) floatHigh=true;
    
  // Here's what we do if we're just out of feeding mode...
  if (ReefAngel.DisplayedMenu==DEFAULT_MENU && isFeeding) {
    isFeeding=false; 
    feedDelay=true; // This will let us know we want some extra time before Smart_NTM
    setRFtimer(30); // Start Smart_NTM in 30 minutes...
  } else if (vtOverride && rfTimer.IsTriggered()) { // Our RF timer is over. 
    vtOverride=false; // Stop overriding the default RF mode

    // First let's deal with that extra 30 minutes
    if(feedDelay) {
      feedDelay=false; // Reset the feedDelay flag
      setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration); // Smart_NTM time!
    } else {
      // Otherwise go to Previous settings
      setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration); 
    }
  } else   {
    setRFmode(); // Update the mode if we change it remotely
  }
  
  // ATO Refill mode. Top off ATO reservoir until it's at 100%    
  if (InternalMemory.read(Mem_B_RefillATO)==1) {
     if (ReefAngel.WaterLevel.GetLevel()<100) {
       ReefAngel.Relay.On(Extension);
     } else {
       ReefAngel.Relay.Off(Extension);
       InternalMemory.write(Mem_B_RefillATO, 0);
     }
  }

  // Turn off return pump if we run out of water!
  if (ReefAngel.LowATO.IsActive()) {
    bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
  } 
  
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE) {
    // Start automatic water change here.
    // This function is currently modified to work with the float switch as-is.
    ReefAngel.SingleATOHigh(Extension); // Refill from SW bucket

    wcReady=InternalMemory.read(Mem_B_WaterChange); // Trigger to start
    wcFillTime=InternalMemory.read_int(Mem_I_WCFillTime); 
    // Let's get started
    if(wcReady) {
      wcTimer.SetInterval(wcFillTime); // One bucket at a time
      wcTimer.Start();
      InternalMemory.write(Mem_B_WaterChange, 0);
      bitSet(ReefAngel.Relay.RelayMaskOff,Reactor-1); // Start draining
    } 
    if(wcTimer.IsTriggered()) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Reactor-1); // Stop draining
    }    
  } else { 
    // Find out if we are on vacation
    ReefAngel.CustomVar[Var_Vacation]=InternalMemory.read(Mem_B_Vacation);
    vacationMode=ReefAngel.CustomVar[Var_Vacation];
 
    // We're on vacation. Keep the ATO reservoir filled.
    if (vacationMode==1) {
      ReefAngel.WaterLevelATO(Extension,30,61,63);
    } else {
      ReefAngel.Relay.Off(Extension);
    }

    // Turn off return if we are somehow overflowing the sump
    if (ReefAngel.HighATO.IsActive()) {
      if (!floatHigh) {
        floatHigh=true;
       ReefAngel.CustomVar[Var_HighATO]=1;
       bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
     }  
    } else {
      floatHigh=false;
     ReefAngel.CustomVar[Var_HighATO]=0;
    }  
  }
      
  // Turn off Skimmer if Return pump is shutoff.   
  if (bitRead(ReefAngel.Relay.RelayMaskOff,Return-1)==0) {
    bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);
  }
    
  // Power Outage - Only Return Pump should be active
  if (!ReefAngel.Relay.IsRelayPresent(EXP1_RELAY)) // Expansion Relay NOT present
  {
    powerOutage=true;
    ReefAngel.Relay.Off (Skimmer); 
    ReefAngel.Relay.Off (WhiteLEDs); 
    ReefAngel.Relay.Off (BlueLEDs); 
    ReefAngel.Relay.Off (Extension);
    ReefAngel.Relay.Off (Heater);
    ReefAngel.Relay.Off (Refugium); 
    ReefAngel.Relay.Off (Reactor); 
    ReefAngel.CustomVar[Var_Power]=1;
  }
    
  ////// Place your custom code above here

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

// Menu Code
void MenuEntry1() {
  ReefAngel.FeedingModeStart();
}
void MenuEntry2() {
  ReefAngel.WaterChangeModeStart();
}
void MenuEntry3() {
  byte mode,speed,duration;
  byte prevMode,prevSpeed,prevDur;
  
  mode=vtMode;
  mode++;
  
  if (mode > 9) { 
    mode=0; 
    speed=50; duration=0; // Constant
  } else if (mode == 1) { 
    speed=40; duration=0; // Lagoon
  } else if (mode == 2) { 
    speed=45; duration=0; // Reef Crest
  } else if (mode == 3) {  
    speed=55; duration=10; // Short Pulse
  } else if (mode == 4) {
    speed=55; duration=20; // Long Pulse
  } else if (mode == 6) {
    speed=50; duration=10; // Smart_TSM
  } else if (mode == 5) {
    speed=vtNTMSpeed; duration=vtNTMDuration; // Smart_NTM
  } else if (mode == 7) {
    speed=vtNightSpeed; duration=vtNightDuration; // Night
    mode=9; 
  }  

  // Backup the previous modes. We don't want to change the default...
  prevMode=vtPrevMode; prevSpeed=vtPrevSpeed; prevDur=vtPrevDuration;
  setRFmode(mode,speed,duration);
  vtPrevMode=prevMode; vtPrevSpeed=prevSpeed; vtPrevDuration=prevDur;
  setRFtimer();
  
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry4() {
  // Toggle the refugium light if we choose this menu entry.
  if (bitRead(ReefAngel.Relay.RelayData, Refugium-1)) { // If relay is on.
    // Toggle MaskOff for the light
    bitWrite(ReefAngel.Relay.RelayMaskOff, Refugium-1, 1-bitRead(ReefAngel.Relay.RelayMaskOff, Refugium-1));
  } else { 
    // Toggle the MaskOn for the light
    bitWrite(ReefAngel.Relay.RelayMaskOn, Refugium-1, 1-bitRead(ReefAngel.Relay.RelayMaskOn, Refugium-1));
  }
  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();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8() {
  ReefAngel.SetupCalibrateWaterLevel();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry9() {
  ReefAngel.SetupDateTime();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}

// Custom Main Screen
void DrawCustomMain() {
  char buf[16];
  byte x = 5;
  byte y = 2;
  byte t;

  // Main Header
  // ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 35, y,"Lee's Reef");
  // Had no room for this anymore :(
  
  // Date+Time
  ReefAngel.LCD.DrawDate(x+1, y);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, y+9, 128, y+9);
  
  // Param Header
  y+=12; 
  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);
  pingSerial();
    
  /// Display Sunrise / Sunset (to be calculated later...)
  y+=12; t=x;
  sprintf(buf, "%02d:%02d", sl.GetRiseHour(), sl.GetRiseMinute());
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Rise:"); t+=31;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf); 
  sprintf(buf, "%02d:%02d", sl.GetSetHour(), sl.GetSetMinute()); t+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Set:"); t+=25;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf);
  pingSerial();

  // MoonPhase
  y+=10; 
  ReefAngel.LCD.DrawText(0,255,x,y,"Moon:");
  ReefAngel.LCD.Clear(DefaultBGColor,x+32,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_MAGENTA,255,x+32,y,MoonPhaseLabel());
  pingSerial();
  
  // MoonLight %
  y+=10;
  t = intlength(ReefAngel.PWM.GetDaylightValue()) + 1;  t *= 5;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MoonLights:"); 
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+68, y, 1);
  ReefAngel.LCD.DrawText(DPColor, DefaultBGColor, x+68+t, y, "%");
  pingSerial();

  // Display Water level
  y+=10; t=x;
  ConvertNumToString(buf, ReefAngel.WaterLevel.GetLevel(), 1);
  strcat(buf,"  ");
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"AT0 Level:"); t+=60;
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,t,y,buf);

  // Vortech Mode
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF:"); t+=20;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  if (vtMode == 0) ReefAngel.LCD.DrawLargeText(COLOR_GREEN,255,t,y,"Constant");
  else if(vtMode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Lagoon");
  else if (vtMode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Reef Crest");
  else if (vtMode == 3) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Short Pulse");
  else if (vtMode == 4) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Long Pulse");
  else if (vtMode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Smart NTM");
  else if (vtMode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Tidal Swell");
  else if (vtMode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,t,y,"Night");
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF Speed:"); t+=60;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFSpeed_read()); t+=15;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,"/"); t+=10;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFDuration_read());
  pingSerial();
  
  // Display Water level
  y+=10; t=x;
  if (acclDay > 0) {
    ConvertNumToString(buf, acclDay, 1);
    strcat(buf,"  ");
    ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Acclimation Day:"); t+=100;
    ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,t,y,buf);
  } else {
    ReefAngel.LCD.Clear(DefaultBGColor,x,y,x+(128-x),y+8);
  }
  
  // Relays
  y+=10; t=x+7;
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(t, y, TempRelay);
  pingSerial();
  y+=12;
  TempRelay = ReefAngel.Relay.RelayDataE[0];
  TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawOutletBox(t, y, TempRelay);
  pingSerial();
}

void DrawCustomGraph() {
}

byte PWMSlopeOvernight(byte startHour, byte startMinute, byte endHour, byte
endMinute, byte startPWM, byte endPWM, byte Duration, byte oldValue)
{
  
  unsigned long Start = previousMidnight(now())+((unsigned long)NumMins(startHour, startMinute)*60);
  if (hour()<startHour) Start-=86400;
  unsigned long StartD = Start + (Duration*60);
  unsigned long End = nextMidnight(now())+((unsigned long)NumMins(endHour, endMinute)*60);
  if (hour()<startHour) End-=86400;
  unsigned long StopD = End - (Duration*60);
  if ( now() >= Start && now() <= StartD )
    return constrain(map(now(), Start, StartD, startPWM, endPWM),startPWM,
    endPWM);
  else if ( now() >= StopD && now() <= End )
  {
    byte v = constrain(map(now(), StopD, End, startPWM, endPWM),startPWM,
    endPWM);
    return endPWM-v+startPWM;
  }
  else if ( now() > StartD && now() < StopD )
    return endPWM;

  // lastly return the existing value
  return oldValue;
}

// Similar to MoonLights() but adding in ActinicOffset
void RefugiumLights(byte Relay)
{
  int MinuteOffset=InternalMemory.ActinicOffset_read();
  int onTime=NumMins(InternalMemory.StdLightsOffHour_read(),InternalMemory.StdLightsOffMinute_read())+MinuteOffset;
  int offTime=NumMins(InternalMemory.StdLightsOnHour_read(),InternalMemory.StdLightsOnMinute_read())-MinuteOffset;
  
  ReefAngel.StandardLights(Relay,onTime/60,onTime%60,offTime/60,offTime%60);
}

// Vortech Helper functions
void setRFmode(int mode, int speed, int duration) {

  // Check if mode has changed
  if (mode!=vtMode) {  
    vtPrevMode=vtMode;
    vtMode=mode; 
  
    if (mode!=InternalMemory.RFMode_read()) { 
      InternalMemory.RFMode_write(mode); 
    }
    
    // Fix for coming out of night mode
    if (vtPrevMode==Night) {
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Feeding_Stop,0,0);
      ReefAngel.RF.UseMemory=true;
    }
    
    // Smart_NTM is on timer mode.
    if (vtMode==Smart_NTM) {
      setRFtimer();
    }
  } 

  // Check if speed has changed
  if (speed!=vtSpeed) {  
    vtPrevSpeed=vtSpeed;
    vtSpeed=speed;
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    } 
  }

  // Check if duration has changed
  if (duration!=vtDuration) {  
    vtPrevDuration=vtDuration;
    vtDuration=duration; 
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    }
  }
}
void setRFmode() {
  setRFmode(InternalMemory.RFMode_read(), InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
}

void setRFtimer(int minutes) {
  rfTimer.SetInterval(minutes*60);
  rfTimer.Start();
  vtOverride=true;
}
void setRFtimer() {
  setRFtimer(60);
}
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Ok, the new version is posted in the second post (http://forum.reefangel.com/viewtopic.php?p=17807#p17807) This version incorporates the Automated Water change mode using my Reactor pump (Media Rinsing and Water change in one!!) It also incorporates the new Tide class and a custom RF mode to use it. The tidal gap (difference between high and low tide) is affected by the current MoonPhase() and the Sync / Anti-Sync pumps will switch direction based on Ebb and Flood of the tide. I also add a PWMSlope to transition to Night Mode and maintain the tidal effect.

Any questions, please ask. Testing so far is going well :)
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Had my night speed PWMSlope getting set wrong... all fixed now :)
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

I have turned all my custom code into functions so it should be much easier to borrow bits and pieces. Later, I'll move some of the variables into the functions that don't need to be global to make it even more self-contained.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Added the anti-sync part of the ReefCrestMode function into play. Added moonrise/set calculation.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Implemented Roberto's clever multiple screen display feature :)

Roberto... I'm using LCD.DrawGraph and getting a lot of flicker... is there a better way to call that function?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Lee's Feature Complete PDE

Post by rimai »

Graph has it's own custom section...
You need to do this:

Code: Select all

void DrawCustomGraph()
{
  if (ScreenID==1)
    ReefAngel.LCD.DrawGraph(5, 10);
}
Roberto.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Not working right if I navigate away from the screen and come back it doesn't redraw.... If I make that the default screen then it draws until I leave... how can I trigger it to draw once :)
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Lee's Feature Complete PDE

Post by rimai »

You can't have it being called inside DrawCustomMain() at all.
Just on DrawCustomGraph()
Roberto.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Lee's Feature Complete PDE

Post by lnevo »

Yeah i took it out...if i navigate off the screen and back its blank...how can i trigger it to draw when switching screens.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Lee's Feature Complete PDE

Post by rimai »

Try this:

Code: Select all

//declare this on global
boolean DrawGraph=true;

// This goes in DrawCustomMain()
  switch (ScreenID)
  {
  case 0:
    {
      break;
    }
  case 1:
    if (DrawGraph)
    {
      ReefAngel.LCD.DrawGraph(5, 10);
      DrawGraph=false;
    }
    break;
  }

  if (ReefAngel.Joystick.IsLeft())
  {
    ReefAngel.ClearScreen(DefaultBGColor);
    DrawGraph=true;
    ScreenID--;
  }
  if (ReefAngel.Joystick.IsRight())
  {
    ReefAngel.ClearScreen(DefaultBGColor);
    DrawGraph=true;
    ScreenID++;
  }
  if (ScreenID<0) ScreenID=NumScreens-1;
  if (ScreenID>=NumScreens) ScreenID=0;
Roberto.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

And what will trigger the refresh if I don't switch screens?
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

Nevermind..
Piper
Posts: 296
Joined: Fri Jul 20, 2012 7:13 am
Location: Oakley, CA

Re: Lee's Feature Complete PDE

Post by Piper »

lnevo wrote:Nevermind..
You can't leave me hanging like that! What was the problem and fix?
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Lee's Feature Complete PDE

Post by lnevo »

I still am drawing the graph on DrawCustomGraph()
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Lee's Feature Complete PDE

Post by lnevo »

I currently have screen 0 as my graph, screen 1 is ato and rf status, screen 3 is sun/moon info :)
Piper
Posts: 296
Joined: Fri Jul 20, 2012 7:13 am
Location: Oakley, CA

Re: Lee's Feature Complete PDE

Post by Piper »

Very cool. I'll let you get it all sorted and out check back later today. Then I'll copy your code :)
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Lee's Feature Complete PDE

Post by lnevo »

Its posted and working :)
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Lee's Feature Complete PDE

Post by lnevo »

So I did a lot of cleaning up :) I haven't yet compiled or uploaded anything so for now this post is just a preview of what's to come.

First off, I cleaned up a lot of the functions. The only global variables I have are basically the vortech varialbes and my Tide and SunLocation classes. The big benefit is that most of my functions are 100% self-contained and can be copied pretty easily. My setup() custom code is now like 3 lines and my loop() is also extremely clean as everything has been moved to subroutines.

I have also moved a lot of stuff into memory locations. I really need to make this standard practice so that nothing needs to be hard-coded. To support that, I wrote my own init_memory function so that I could re-arrange the variables, make sure new ones are initialized properly, etc. I'm using memory location 199 as the flag bit to trigger the memory reset. I only run this in setup() so you'll have to flip the flag and reboot the controller. Or flip the flag and upload new code. I also changed a lot of the memory locations and variables to use true/false instead of 1=on 0=off, since it cleans up a lot of code. One of the reasons I needed the init_memory function :)

So, what else is new in the coming version? I've added a few things

1) CalibrateDosingPumps() - I wrote this function as I'm about to finally enable my dosers. You flip the memory bit to true and it will turn on both pumps for 10 minutes. Then you can measure how much fluid was pumped and set your pumps accordingly. It will get used once in a blue moon, but hopefully someone will find it useful.

2) runSwabbie() - This function will run my swabbie (using the DosingPumpRepeat() function but I also added a "manual" mode. If you override the default status of the swabbie port, it will clear the override and run the swabbie for 1 minute. Will be fun to demo for people :)

3) runFeeder() - This uses a memory location as a trigger, but basically will StartFeedingMode() and then wait for a specified delay (stored in memory) and then "press" the auto-feeder button for 5 seconds. I have integrated it into my vacation() mode by flipping on the memory location at 7pm when vacation is enabled. I may change the behavior later on after I get my auto-feeder and mod it and I decide I want it running daily :)

That's it for now. I'll probably have some time this weekend to debug the code (written with Textastic on my iPad) and get it uploaded to the controller. My swabbie is going to be a while and I'm waiting for a bracket for the dosing pumps so still some hardware pending :)
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Lee's Feature Complete PDE

Post by rimai »

Hey Lee,
This actually triggered a very nice idea :)
I'm going to create a handful of function calls that can be triggered using the wifi commands.
Just like /mf that starts feeding mode.
This way, you can call custom functions through the web browser and we harass Curt to implement in the app too :)
By having those function calls, you can start CalibrateDosingPumps() or runSwabbie() for example without having to trigger it through memory bit set.
Roberto.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Lee's Feature Complete PDE

Post by lnevo »

Sounds good :) I'm all about saving writes to memory locations :) i should consolidate some though...its kind of a waste of a byte when you only need a bit...anyway off-track :)

What i wanted to share was however we call the function or memory. It's still a http call. I've made myself a bit of a "control panel" html page with all the links I use as shortcuts. Basically a glorified bookmark page. This way I never need to remember what bit to flip :)
Post Reply