Lee's Feature Complete PDE
Re: Lee's Feature Complete PDE
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 )
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.
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.
-
- Posts: 188
- Joined: Fri Dec 30, 2011 6:57 am
Re: Lee's Feature Complete PDE
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:
Was it necessary to put it there for some reason? You didn't follow the " // This should always be the last line
" comments.
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() {
}
" comments.
Re: Lee's Feature Complete PDE
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.TanksNStuff wrote:Was it necessary to put it there for some reason? You didn't follow the " // This should always be the last lineCode: Select all
////// Place your custom code above here // This should always be the last line ReefAngel.Portal("lnevo"); ReefAngel.ShowInterface(); }
" comments.
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
-
- Posts: 188
- Joined: Fri Dec 30, 2011 6:57 am
Re: Lee's Feature Complete PDE
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.
Re: Lee's Feature Complete PDE
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.
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()...
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 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);
}
Re: Lee's Feature Complete PDE
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.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.
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.
Re: Lee's Feature Complete PDE
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...
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...
Re: Lee's Feature Complete PDE
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
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
Re: Lee's Feature Complete PDE
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);
}
Re: Lee's Feature Complete PDE
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
Any questions, please ask. Testing so far is going well
Re: Lee's Feature Complete PDE
Had my night speed PWMSlope getting set wrong... all fixed now
Re: Lee's Feature Complete PDE
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.
Re: Lee's Feature Complete PDE
Added the anti-sync part of the ReefCrestMode function into play. Added moonrise/set calculation.
Re: Lee's Feature Complete PDE
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?
Roberto... I'm using LCD.DrawGraph and getting a lot of flicker... is there a better way to call that function?
Re: Lee's Feature Complete PDE
Graph has it's own custom section...
You need to do this:
You need to do this:
Code: Select all
void DrawCustomGraph()
{
if (ScreenID==1)
ReefAngel.LCD.DrawGraph(5, 10);
}
Roberto.
Re: Lee's Feature Complete PDE
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
Re: Lee's Feature Complete PDE
You can't have it being called inside DrawCustomMain() at all.
Just on DrawCustomGraph()
Just on DrawCustomGraph()
Roberto.
Lee's Feature Complete PDE
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.
Re: Lee's Feature Complete PDE
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.
Re: Lee's Feature Complete PDE
And what will trigger the refresh if I don't switch screens?
Re: Lee's Feature Complete PDE
You can't leave me hanging like that! What was the problem and fix?lnevo wrote:Nevermind..
Lee's Feature Complete PDE
I still am drawing the graph on DrawCustomGraph()
Lee's Feature Complete PDE
I currently have screen 0 as my graph, screen 1 is ato and rf status, screen 3 is sun/moon info
Re: Lee's Feature Complete PDE
Very cool. I'll let you get it all sorted and out check back later today. Then I'll copy your code
Re: Lee's Feature Complete PDE
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
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
Re: Lee's Feature Complete PDE
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.
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.
Lee's Feature Complete PDE
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
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