More troubles.. Why didn't it go in to feeding mode?

Basic / Standard Reef Angel hardware
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

A little background - I am in the process of upgrading my 60 to a 120. I bought an additional RA (this one analog) and I am in the process of slowly migrating all the modules.

I have this code which puts the RA in to feeding mode at 7:30am. It works on the 60 but is not working on the 120.

Code: Select all

if ( ((hour() == 7)) && (minute() == 30) &&(second() == 0) ) ReefAngel.FeedingModeStart(); 
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: More troubles.. Why didn't it go in to feeding mode?

Post by rimai »

Same code?
Can you post the entire code you uploaded in the 120?
Roberto.
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

rimai wrote:Same code?
Can you post the entire code you uploaded in the 120?
absolutely, and thank you. Mind you, I've only witnessed it not going in to feed mode this morning. I will keep an eye on it.

Code: Select all

////  Port 1			Heater
////  Port 2			ATO pump
////  Port 3			Feeder
////  Port 4			Protein Skimmer
////  Port 5			Return Pump
////  Port 6			Wavemakers
////  Port 7                    UV Sterilizer
////  Port 8                    Cabinet Light

////  BOX 1 PORT 1              Calcium Doser
////  BOX 1 PORT 2              Alkalinity Doser
////  BOX 1 PORT 8              Sump Fan
////  BOX 1 PORT 8              Fans

////  Probe T1  SUMP
////  Probe T2  Tank
////  Probe T3  Canopy


#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>
#include <DCPump.h>

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

#define Heater Port1
#define Topoff Port2
#define Feeder Port3
#define Skimmer Port4
#define Return Port5
#define Wave Port6
#define UVlight Port7
#define Fugelight Port8
#define CanopyFan  Box1_Port8
#define CalcDose  Box1_Port1
#define AlkDose  Box1_Port2
#define SumpFan  Box1_Port7

#define FugelightBit   1<<7
#define UVlightBit   1<<6
#define WaveBit   1<<5
#define ReturnBit   1<<4
#define SkimmerBit   1<<3
#define FeederBit   1<<2
#define TopoffBit   1<<1
#define HeaterBit   1<<0

static byte wpMode;
static byte wpWavStr;
static byte wpWavOff;

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

void setup()
{
// This must be the first line
    ReefAngel.Init();  //Initialize controller
    ReefAngel.Use2014Screen(); // Let's use 2014 Screen 
    ReefAngel.AddMultiChannelWaterLevelExpansion();  // Multi-Channel Water Level Expansion Module
    ReefAngel.Network.WifiAuthentication("Smotz:-------------");
    
// Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = SkimmerBit | ReturnBit | TopoffBit | UVlightBit;
// Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = HeaterBit | SkimmerBit | ReturnBit | TopoffBit | WaveBit | UVlightBit | FeederBit;
// Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = FugelightBit;
// Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = HeaterBit | TopoffBit | SkimmerBit | ReturnBit | WaveBit | UVlightBit | FeederBit;

// Use T2 (Tank) probe as temperature and overheat functions
    ReefAngel.TempProbe = T2_PROBE;
    ReefAngel.OverheatProbe = T2_PROBE;

// Ports that are always off
    ReefAngel.Relay.Off( Feeder );
    ReefAngel.Relay.Off( Topoff );

// Ports that are always on
    ReefAngel.Relay.On( Box1_Port3 );
    ReefAngel.Relay.On( Box1_Port4 );    
    ReefAngel.Relay.On( Box1_Port5 );
    ReefAngel.Relay.On( Box1_Port6 );
    ReefAngel.Relay.On( Box1_Port7 );  

// DCPUMP
    ReefAngel.DCPump.FeedingSpeed=35;
    ReefAngel.DCPump.WaterChangeSpeed=0;
    ReefAngel.DCPump.ActinicChannel=Sync; 
    ReefAngel.DCPump.DaylightChannel=AntiSync; 

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

void loop()
{
    ReefAngel.Relay.On( Return );
    ReefAngel.Relay.On( Wave );
    ReefAngel.Relay.Off( Feeder );
    ReefAngel.MoonLights( Fugelight );
    ReefAngel.StandardHeater( Heater );
    ReefAngel.StandardFan( SumpFan );
    
////// Place your custom code below here

// Main Top Off
   ReefAngel.WaterLevelATO(1,Topoff,15,85,95);  
// just to be safe if the water level gets to 140 or greater, turn off the topoff.
//    if (ReefAngel.WaterLevel.GetLevel(1)<=85) ReefAngel.Relay.On(Topoff); // Obsolete code 
//    if (ReefAngel.WaterLevel.GetLevel(1)>=95) ReefAngel.Relay.Off(Topoff); // Obsolete code
    if ( ReefAngel.WaterLevel.GetLevel(1) >= 140 ) ReefAngel.Relay.Override (Topoff,0);
// End Main Top Off 

//Dosing
    ReefAngel.DosingPumpRepeat1( CalcDose );
    ReefAngel.DosingPumpRepeat2( AlkDose );
//// 30,20 = 17.5 ml day
//// ReefAngel.DosingPumpRepeat(CalcDose,0,30,20);
//// ReefAngel.DosingPumpRepeat(AlkDose,10,30,20);

// Turn on Canopy Fans when the temp of T3 (Canopy) gets above 85.0 degrees
    if ( ReefAngel.Params.Temp[T3_PROBE] >= 850 ) ReefAngel.Relay.On( CanopyFan );
// Turn off Canopy Fans when the temp of T2 (Canopy) gets below 80.0 degrees
    if ( ReefAngel.Params.Temp[T3_PROBE] < 800 ) ReefAngel.Relay.Off( CanopyFan );
    
// Make Salinity and PH calibration changes on the fly without reboot    
//    ReefAngel.SalMax=InternalMemory.SalMax_read();  
//    ReefAngel.PHMin=InternalMemory.PHMin_read();
//    ReefAngel.PHMax=InternalMemory.PHMax_read();

    ReefAngel.Relay.DelayedOn(Skimmer,5); 
    
// Buzzer if temp is too high or low, or waterlevel 1 is too high or too low.
    if (ReefAngel.DisplayedMenu!=WATERCHANGE_MODE && ReefAngel.DisplayedMenu!=FEEDING_MODE) // Only check if not Feeding Mode or Water Change Mode
    {  
    if ( ReefAngel.Params.Temp[T2_PROBE] < 700 || ReefAngel.Params.Temp[T2_PROBE] > 850 || ReefAngel.WaterLevel.GetLevel(1) > 140 || ReefAngel.WaterLevel.GetLevel(1) < 70)
        {   
        pinMode(lowATOPin,OUTPUT);
        digitalWrite(lowATOPin,HIGH);
        }
        else
        {
        pinMode(lowATOPin,OUTPUT);
        digitalWrite(lowATOPin,LOW);
    }}

// Turn the fugelight on if the return is off 
    if (ReefAngel.Relay.Status ( Return ) == 0) ReefAngel.Relay.On( Fugelight );
  
// EMERGENCY SUMP WATER LEVEL BELOW 25% AND WATERCHANGE MODE IS NOT ON AND WAIT FOR CONTROLLER TO BE ON FOR 5 SECONDS
//   if ( ReefAngel.WaterLevel.GetLevel(1) <= 25 && ReefAngel.DisplayedMenu!=WATERCHANGE_MODE && millis() > 5000)
//   {
//   ReefAngel.Relay.Override(Return,0);
//   ReefAngel.Relay.Override(Skimmer,0);
//   ReefAngel.Relay.Override(UVlight,0);
//   ReefAngel.Relay.Override(Feeder,0);
//   ReefAngel.Relay.Override(CalcDose,0);
//   ReefAngel.Relay.Override(AlkDose,0);
//   ReefAngel.Relay.Override(Fugelight,1);
//   }
// END EMERGENCY WATER LEVEL ROUTINE

// Feeding Mode
// if the hour is 7a and minute is 30 and seconds is 0 start the feeding mode
    if ( ((hour() == 7)) && (minute() == 30) &&(second() == 0) ) ReefAngel.FeedingModeStart(); 
    if ( ((hour() == 7)) && (minute() == 31) &&(second() == 0) ) ReefAngel.Relay.On(Feeder); //TURN FEEDER RELAY ON at 7:31:00
    if ( ((hour() == 7)) && (minute() == 31) &&(second() == 5) ) ReefAngel.Relay.Off(Feeder); //TURN FEEDER RELAY OFF at 7:31:02
    if ( ((hour() == 7)) && (minute() == 33) &&(second() == 0) ) ReefAngel.Relay.On(Feeder); //TURN FEEDER RELAY ON at 7:33:00
    if ( ((hour() == 7)) && (minute() == 33) &&(second() == 5) ) ReefAngel.Relay.Off(Feeder); //TURN FEEDER RELAY OFF at 7:33:02
// end feeding mode

// Custom Wave Routine 
    if (InternalMemory.DCPumpMode_read()==11)  
{
    ReefAngel.DCPump.UseMemory=false;
// set the wpMode based on what time it is
    if ( (hour() >= 2) && (hour() < 5) ) wpMode=1;       // from 2am - 5am  
    if ( (hour() >= 5) && (hour() < 8) )  wpMode=2;      // from 5am - 8am
    if ( (hour() >= 8) && (hour() < 11) ) wpMode=4;      // from 8am - 11am  Nutrient Transport
    if ( (hour() >= 11) && (hour() < 14) ) wpMode=2;     // from 11a - 2pm
    if ( (hour() >= 14) && (hour() < 17) ) wpMode=3;     // from 2pm - 5pm
    if ( (hour() >= 17) && (hour() < 20) ) wpMode=2;     // from 5pm - 8pm
    if ( (hour() >= 20) && (hour() < 23) ) wpMode=3;     // from 8pm - 11p
    if (hour() >= 23) wpMode=2;                          // from 11pm - midnight 
    if (hour() < 2) wpMode=1;                            // from midnight - 2am
      
    switch (wpMode) 
    {
    case 1:  wpWavStr=35; wpWavOff=10; break;  //Night Mode
    case 2:  wpWavStr=37; wpWavOff=4; break;
    case 3:  wpWavStr=42; wpWavOff=7; break;
    case 4:  wpWavStr=50; wpWavOff=10; break;  //Nutrient Transport
    default: wpWavStr=35; wpWavOff=2;
    }
//  Night Mode
    if (wpMode==1) ReefAngel.DCPump.SetMode (Gyre, wpWavStr, wpWavOff);
        
//If 8am - 11am, Nutrient Transport   
    if (wpMode==4) ReefAngel.DCPump.SetMode (NutrientTransport, wpWavStr,wpWavOff);
        
//Wave for everything else        
    if (wpMode!=4 && wpMode!=1) ReefAngel.DCPump.SetMode (Else, wpWavStr, wpWavOff);       
    }
    else ReefAngel.DCPump.UseMemory = true;    //  If it's not custom mode on the portal, then do what mode the portal says.
//  End Custom Wave Routine  

//  Only turn on UV Sterilizer between 11pm and 3am
    if ( (hour() >= 3) && (hour() < 23) )  // from 3a - 11p
    ReefAngel.Relay.Off(UVlight);
    else ReefAngel.Relay.On(UVlight);

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

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

void DrawCustomMain()
{
// Parameters
#if defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 5, ReefAngel.Params,
    ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue() );
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 5, ReefAngel.Params );
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
    pingSerial();

//    Salinity
//    ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,20,80, "SAL:" );
//    ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,44,80, ReefAngel.Params.Salinity );
//    pingSerial();

// Main Relay Box
    byte TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox( 12, 95, TempRelay );
    pingSerial();
// Relay Expansion
    TempRelay = ReefAngel.Relay.RelayDataE[0];
    TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
    TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
    ReefAngel.LCD.DrawOutletBox( 12, 105, TempRelay );
    pingSerial();
// Date and Time
    ReefAngel.LCD.DrawDate( 6, 122 );
    pingSerial();
//draw the mode on the screen
    char buf[16];
    char buf2[16];
//    char buf3[32];
    sprintf(buf,"ELSE %d%% +/- %d%%",wpWavStr,wpWavOff);
    sprintf(buf2,"Wave Mode = %d%",wpMode);
//    sprintf(buf3,"Return Power = %d%",InternalMemory.LEDPWMActinic_read());
//    ReefAngel.LCD.DrawText(0,255,10,40,buf3);
    ReefAngel.LCD.DrawText(0,255,20,60,buf);
    ReefAngel.LCD.DrawText(0,255,20,50,buf2);
}

void DrawCustomGraph()
{
}
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

Went in to feeding this morning. Just a quirk maybe?
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

No feeding mode this morning. :?:
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

Let me preface this by saying I don't own a ReefAngel yet, but I do have a lot of Arduino, C and C++ experience.

I'm not sure what the cycle time of the code is, but seeing how everything in an Arduino is in one giant loop, there is going to be some sort of periodicity for when individual checks are run. It is highly unlikely that that the period is more than 1 second, but MAYBE if it is, then this could explain why your seeing this issue.

In the first line of your feeder code you have:

Code: Select all

if ( ((hour() == 7)) && (minute() == 30) &&(second() == 0) )
So that code is only going to run if second == 0 exactly. If the cycle time of your code is more than 1 second than there is a possibility that it might get missed. One thing you could do would be to write something like this:

Code: Select all

unsigned long feedStartTS = 0;

// Grab timestamp if we don't have one, and it's the right time
// This should only run once at 7:30 or slightly after
if ( (feedStartTS == 0) && (hour() == 7) && (minute() >= 30) ) {
    feedStartTS = millis();
}

if (feedStartTS) {

    deltaTS = millis() - feedStartTS;

    if ( deltaTS >= 600000 ) { // 10 minutes has elapsed

        // Do something
        
        // Set timestamp to 0 so we stop doing feeder stuff since this is the last stage 
        feedStartTS = 0; 

    } else if ( deltaTS >= 300000 ) { // 5 minutes has elapsed
        // Do something
    } else if ( deltaTS >= 120000 ) { // 2 minutes has elapsed
        // Do something
    } else if ( deltaTS >= 60000 ) { // 1 minute has elapsed
        // Do something
    } else {
       // Start feeding mode
    }
}
I wrote this code off the cuff and have not tested it. Try it at your own risk. It probably won't even compile initially. I just wanted to write it as a solution for what might not even be your issue. As an outsider though, since I don't have a ReefAngel, it is the only issue I can see with your code.

Notice with this code the if statements flow in reverse order, meaning the last thing you do happens first. One of the assumptions I am making with this code is that it is OK to call the "//Do something" code more than once as it will be continuously called until we enter the next stage.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by lnevo »

Or easier just take off the second() test altogether.
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

lnevo wrote:Or easier just take off the second() test altogether.
That would work too, but it looks like he is trying to turn things on for amounts of time that are less than a minute. Which means he will need to use something smaller than a minute.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by lnevo »

Starting feeding mode wouldnt be a problem to continue running for the minute. Think about it, there's as much potential of it going multiple times in that second already.
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

lnevo wrote:Starting feeding mode wouldnt be a problem to continue running for the minute. Think about it, there's as much potential of it going multiple times in that second already.
I should have been more specific it isn't for feed mode that he needs the sub-minute resolution it is for his auto-feeder. He is turning it on for only five seconds, and then turning it off. I agree that getting rid of the seconds() for the feed mode would work but he will still need it for the auto feeder part.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by lnevo »

Smotz wrote:No feeding mode this morning. :?:
Mode... Not feeder.

But even if its an autofeeder. It usually is a hack to close the relay. It usually will only trigger one feeding for a button press so no need to have a timer. If it holds the button for one second or one minute it should be fine. At least with an eheim.
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

thanks all. I will remove the seconds from the feed mode and see if that helps. Yes the other part is the autofeeder and that doesn't seem to be a problem.
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

Give this a shot, but keep in mind that if it was in fact the problem, you might now have the same exact problem with the feeder too since you are also using seconds in those lines! This is the point I was trying to make. It would be really bad if your feeder turned on but you happened to miss the specific second where you are trying to turn it off, and then it never turns off!

Make sure you keep an eye on this! At a minimum I would change the line where you turn the feeder off to be a greater than or equal check on seconds, that way you know you will be guaranteed to turn the feeder off. I would rather miss turning the feeder on than miss turning it off and pouring a ton of food into the tank.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by lnevo »

Look at the function I have for my Swabbie and autofeeder. It follows what re76's example is doing too
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

re76 wrote:Give this a shot, but keep in mind that if it was in fact the problem, you might now have the same exact problem with the feeder too since you are also using seconds in those lines! This is the point I was trying to make. It would be really bad if your feeder turned on but you happened to miss the specific second where you are trying to turn it off, and then it never turns off!

Make sure you keep an eye on this! At a minimum I would change the line where you turn the feeder off to be a greater than or equal check on seconds, that way you know you will be guaranteed to turn the feeder off. I would rather miss turning the feeder on than miss turning it off and pouring a ton of food into the tank.
Odd because it worked for years on my other (PWM) RA. As a matter of fact, it still does. I think this new RA may be 'sluggish' - is that even possible ?
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

lnevo wrote:Look at the function I have for my Swabbie and autofeeder. It follows what re76's example is doing too

Dude, your code is too advanced. I could barely read it.
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

Smotz wrote:
re76 wrote:Give this a shot, but keep in mind that if it was in fact the problem, you might now have the same exact problem with the feeder too since you are also using seconds in those lines! This is the point I was trying to make. It would be really bad if your feeder turned on but you happened to miss the specific second where you are trying to turn it off, and then it never turns off!

Make sure you keep an eye on this! At a minimum I would change the line where you turn the feeder off to be a greater than or equal check on seconds, that way you know you will be guaranteed to turn the feeder off. I would rather miss turning the feeder on than miss turning it off and pouring a ton of food into the tank.
Odd because it worked for years on my other (PWM) RA. As a matter of fact, it still does. I think this new RA may be 'sluggish' - is that even possible ?
Have you added more extensions and functionality since then?
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

re76 wrote:Give this a shot, but keep in mind that if it was in fact the problem, you might now have the same exact problem with the feeder too since you are also using seconds in those lines! This is the point I was trying to make. It would be really bad if your feeder turned on but you happened to miss the specific second where you are trying to turn it off, and then it never turns off!

Make sure you keep an eye on this! At a minimum I would change the line where you turn the feeder off to be a greater than or equal check on seconds, that way you know you will be guaranteed to turn the feeder off. I would rather miss turning the feeder on than miss turning it off and pouring a ton of food into the tank.
It 'should' never dump the feeder continually. The relay is a "button push" - the feeder rotates once upon pressing it.
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

re76 wrote:
Smotz wrote:
re76 wrote:Give this a shot, but keep in mind that if it was in fact the problem, you might now have the same exact problem with the feeder too since you are also using seconds in those lines! This is the point I was trying to make. It would be really bad if your feeder turned on but you happened to miss the specific second where you are trying to turn it off, and then it never turns off!

Make sure you keep an eye on this! At a minimum I would change the line where you turn the feeder off to be a greater than or equal check on seconds, that way you know you will be guaranteed to turn the feeder off. I would rather miss turning the feeder on than miss turning it off and pouring a ton of food into the tank.
Odd because it worked for years on my other (PWM) RA. As a matter of fact, it still does. I think this new RA may be 'sluggish' - is that even possible ?
Have you added more extensions and functionality since then?

Not sure I understand your question? I have been slowly moving the modules from my PWM RA to the Analog RA.

Standard stuff - 2 relay boxes, multi water level, expansion hub, wifi, bluetooth
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

Smotz wrote:
re76 wrote:Give this a shot, but keep in mind that if it was in fact the problem, you might now have the same exact problem with the feeder too since you are also using seconds in those lines! This is the point I was trying to make. It would be really bad if your feeder turned on but you happened to miss the specific second where you are trying to turn it off, and then it never turns off!

Make sure you keep an eye on this! At a minimum I would change the line where you turn the feeder off to be a greater than or equal check on seconds, that way you know you will be guaranteed to turn the feeder off. I would rather miss turning the feeder on than miss turning it off and pouring a ton of food into the tank.
It 'should' never dump the feeder continually. The relay is a "button push" - the feeder rotates once upon pressing it.
That is good to know. I am not a Reef Angel expert by any means, and in most non-reef angel cases I've encountered setting an output high would leave it on until you set it low again. My background is in embedded software for medical devices though where everything is super strict so I have a tendency to be extra careful...
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

re76 wrote:
Smotz wrote:
re76 wrote:Give this a shot, but keep in mind that if it was in fact the problem, you might now have the same exact problem with the feeder too since you are also using seconds in those lines! This is the point I was trying to make. It would be really bad if your feeder turned on but you happened to miss the specific second where you are trying to turn it off, and then it never turns off!

Make sure you keep an eye on this! At a minimum I would change the line where you turn the feeder off to be a greater than or equal check on seconds, that way you know you will be guaranteed to turn the feeder off. I would rather miss turning the feeder on than miss turning it off and pouring a ton of food into the tank.
It 'should' never dump the feeder continually. The relay is a "button push" - the feeder rotates once upon pressing it.
That is good to know. I am not a Reef Angel expert by any means, and in most non-reef angel cases I've encountered setting an output high would leave it on until you set it low again. My background is in embedded software for medical devices though where everything is super strict so I have a tendency to be extra careful...
Well, your help is very much appreciated. I think you nailed it when you said it is 'missing the second'. I suspect this RA may be 'sluggish' or something.
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

To clarify a bit. The Reef Angel is based off of the Arduino platform. The Arduino tries to makes things simple for the end user by having only two important functions that are needed: a setup() function and loop() function.

The loop function gets called by the arduino as much as possible. If you have a really basic loop function then it might be able to call it 1000 times a second. It can't call it again though until the loop function is finished from the last time it was called. So as your loop() gets more and more code in it it will be getting called less times every second.

Not to mention for every new extension you add to the RA there is more library code to support it. As an end user you don't see this a lot unless you go looking for it. This is why I asked if you had added more extensions or features. As you add complexity to your code it is going to run a bit slower. This isn't necessarily a bad thing, it just is. It is a standard understood trade off for all embedded systems whether they are using Arduino or not.

There is a concept in software development called defensive programming. It is the idea that you make your code robust enough to handle unforeseen conditions. This is why I am a big advocate of using >= or <= instead of == wherever possible. You sometimes have to work your logic a bit differently but it usually isn't a lot more work, and it ensures that if for some crazy reason you don't catch something on the first loop through you will get it on the second time around, and will never just miss it totally like you can with ==.

Hope this makes sense and isn't just causing more confusion!
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by lnevo »

Your code was good just sometimes we foresake complexity for ease of troubleshooting and readability :) welcome to the club :)
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

re76 wrote:To clarify a bit. The Reef Angel is based off of the Arduino platform. The Arduino tries to makes things simple for the end user by having only two important functions that are needed: a setup() function and loop() function.

The loop function gets called by the arduino as much as possible. If you have a really basic loop function then it might be able to call it 1000 times a second. It can't call it again though until the loop function is finished from the last time it was called. So as your loop() gets more and more code in it it will be getting called less times every second.

Not to mention for every new extension you add to the RA there is more library code to support it. As an end user you don't see this a lot unless you go looking for it. This is why I asked if you had added more extensions or features. As you add complexity to your code it is going to run a bit slower. This isn't necessarily a bad thing, it just is. It is a standard understood trade off for all embedded systems whether they are using Arduino or not.

There is a concept in software development called defensive programming. It is the idea that you make your code robust enough to handle unforeseen conditions. This is why I am a big advocate of using >= or <= instead of == wherever possible. You sometimes have to work your logic a bit differently but it usually isn't a lot more work, and it ensures that if for some crazy reason you don't catch something on the first loop through you will get it on the second time around, and will never just miss it totally like you can with ==.

Hope this makes sense and isn't just causing more confusion!

Hi!

Working off your example and a good amount of reading I put the below code together in an effort to be more efficient. I am trying to set the feeding mode twice a day and bounce the feeding relay for 10 seconds.

I set "static time_t NoteTime=millis();" as a global variable so I can call it in other parts of the code.

Code: Select all

[code]//FEEDING MODE
// Begin Feeding Mode
    if ( ((hour() == 7)) && (minute() == 30) || ((hour() == 18)) && (minute() == 00)) {
      ReefAngel.FeedingModeStart(); // FEEDING MODE @ 7:30 AM or 6:00 PM
      
      NoteTime = millis(); 
      unsigned long DeltaTS = millis() - NoteTime;
      
      if ( DeltaTS >= 60000 ) ReefAngel.Relay.On(Feeder); // turn on after 1 minute
      if ( DeltaTS >= 70000 ) ReefAngel.Relay.On(Feeder); // turn off shortly after 
      if ( DeltaTS >= 120000 ) ReefAngel.Relay.On(Feeder); // turn on after 2 minutes
      if ( DeltaTS >= 130000 ) ReefAngel.Relay.On(Feeder); // turn off shortly after
    }
[/code]
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

This is a really good start a few things though. I wouldn't use time_t, if you are intending it to store the output of a call to millis() you might want to change it to static unsigned long, which is what millis() returns. As far as I know time_t only has second accuracy and not millisecond accuracy so I'm not sure what your deltaTS will have in it after the subtraction since you are subtracting two different types.

Next up is your logic for the timing of the feeding relay. You should be using if-else-if statements. You only want one thing to happen every time, not multiple. As you have written above, if your DeltaTS is bigger than 130000 then all of those cases would trigger, which I don't think is what you want.

Take a look at the code I posted previously again and notice how I used several if-else-if statements. Also notice how I have the case with the biggest deltaTS first. That is on purpose so that it doesn't do multiple cases on each pass through he code.

Next, somewhere in this code you need to add a check to make sure you don't ALWAYS run this code. There are several ways to do this. You could use a Boolean variable that you set to true in your "begin feeding mode" code and then set to false in your last step where you turn your feeder off. Then wrap all of the feede logic in a big if statement that checks that variable.

Finally, and this is me being nitpicky, you probably don't need to be using a static variable here. All of the user code is in the arduino loop() function, you will probably never use NoteTime out of loop() so it would probably be fine to not be static. It is good practice to avoid static variables where possible.

Also You are always turning the feeder on. Some of those should be an off call.

Sorry I can't write any code examples for you, I am writing this on my phone. Let me know if I need to elaborate more about anything!


Sent from my iPhone using Tapatalk
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

This is great! Learning..
You're right - I am always turning it on - that was a CTRL-C error :)

After reading what you wrote 3 times I now understand that all of my cases will trigger @ 130000. I will work on the else statements.

Regarding the use of the static global variable - I am actually going to use it a few times in the code - like for my ATO - I want to ensure it waits several seconds after feeding and waterchange mode before it checks for the ATO timeout. For instance, I have this code also:

Code: Select all

if (ReefAngel.WaterLevel.GetLevel(1) <= 25 && ReefAngel.DisplayedMenu!=WATERCHANGE_MODE)
   {
     NoteTime = millis(); 
     unsigned long DeltaTS = millis() - NoteTime;
     if ( DeltaTS >= 15000 )
   {    
       ReefAngel.Relay.Override(Return,0);
       ReefAngel.Relay.Override(Skimmer,0);
       ReefAngel.Relay.Override(UVlight,0);
       ReefAngel.Relay.Override(Feeder,0);
       ReefAngel.Relay.Override(CalcDose,0);
       ReefAngel.Relay.Override(AlkDose,0);
       ReefAngel.Relay.Override(Fugelight,1);
         pinMode(lowATOPin,OUTPUT);  //Buzzer
         digitalWrite(lowATOPin,HIGH); //Buzzer
    }}
// END EMERGENCY WATER LEVEL ROUTINE
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

More troubles.. Why didn't it go in to feeding mode?

Post by lnevo »

It doesn't need to be static if you set it every time to millis() but it may need to be global only if you are using it in other functions outside of loop. If you are setting it once and want it retained like a flag that you want to set if something happens then you'll want to use static.

Also time_t is an unsigned long so no difference here.
re76
Posts: 14
Joined: Tue Jul 19, 2016 7:55 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by re76 »

lnevo wrote:It doesn't need to be static if you set it every time to millis() but it may need to be global only if you are using it in other functions outside of loop. If you are setting it once and want it retained like a flag that you want to set if something happens then you'll want to use static.

Also time_t is an unsigned long so no difference here.
You are correct that time_t is an unsigned long, and it will work in this scenario. It is intended however to work with the time.h library which stores the seconds since epoch (seconds since 1970), which is a lot of seconds. Hence why it is an unsigned long. The call to millis() returns the millisecond counter (also very big).

By making a new type just for the time library, it helps keep track of what the variable is intended to be used for. When I see someone using time_t to store the millisecond counter value, it makes me worried they will try to use it with the time library somewhere down the line and not understand why it isn't working.

It is fine to keep using it as long as you don't try to use it with any of the functions in time.h, but for readability and code clarity I still think unsigned long is the better choice.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: More troubles.. Why didn't it go in to feeding mode?

Post by lnevo »

Fair point. :)
Smotz
Posts: 412
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA

Re: More troubles.. Why didn't it go in to feeding mode?

Post by Smotz »

here is my updated code with the else's incorporated

Code: Select all

//FEEDING MODE
// Begin Feeding Mode
    if (((hour() == 7)) && (minute() == 30) || (hour() == 18) && (minute() == 00)) {
      ReefAngel.FeedingModeStart(); // FEEDING MODE @ 7:30 AM or 6:00 PM
      NoteTime = millis(); 
      unsigned long DeltaTS = millis() - NoteTime;
      if ( DeltaTS >= 130000 ) ReefAngel.Relay.Off(Feeder); // turn off 2 minutes 10 secs 
      else
      if ( DeltaTS >= 120000 ) ReefAngel.Relay.On(Feeder); // turn on after 2 minutes
      else
      if ( DeltaTS >= 70000 ) ReefAngel.Relay.Off(Feeder); // turn off 1 min 10 secs 
      else
      if ( DeltaTS >= 60000 ) ReefAngel.Relay.On(Feeder); // turn on after 1 minute
      }
Post Reply