Controlling a relay (not relay box)

Basic / Standard Reef Angel hardware
Post Reply
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Controlling a relay (not relay box)

Post by egadgetjnr »

I seem to be posting a bit lately. (I keep getting more ideas :p)

I have a quick question and hopefully it will be a quick answer.

I have a ozone unit that is manually controlled (will not turn on auto magically when plugged into live power, you have to press an on switch)

Now I'm looking at controlling the on switch using a relay, but I'm unsure as to how I will be able to control/power the relay. Am I able to use PWM at all? Or is there something else I could do?
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

This is similar to the mod i did on my eheim auto-feeder. You need to bypass the switch that has the manual on. You can solder the pins on the switch to a relay (5v or 12v) then connect the relay to a small wall wart transformer (usb charger is 5v usually...) then you just need to turn the relay the wall wart is plugged into for a few seconds to simulate a button press. The main power no longer needs to be on the RA unless you want to override and ensure it cant be turned on..
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

Ahhhhh! The good old wall wart. I think I might do that. I only need it to trigger momentarily (about 1 second or maybe less)
Could I also use a pin on the same relay (double pole I guess) that can tie in with my IO module to ensure it closes/turns off after it's been triggered?)

I saw the auto feeder in your code (I'm going through your code and studying it by the way, I really love how nice and clean and neat it is! I'm using some if the neatness ideas in mine. I hope that's ok? :p
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

Please do! Thats why I post it and keep it updated...

You could...if you have the io module you could just connect it directly to that and do the on/off through the i/on module. No relay required :)

Take a look at the autofeeder thread...i believe the code is there for using the io module to do it...
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

Eheim-autofeeder

http://forum.reefangel.com/viewtopic.php?t=1415

The code is in there later in the thread..i don't know if thats the "simplest" approach though...there may be an easier way to output to the io channel...
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

Oh! You can do that? Is there a max voltage/amperage you can out through it? Does it kinda become a relay itself?
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

I think it's pretty much open and close, but I don't have an IO module so I don't know.
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

Ok, I'm stuck. lol.
Until I can figure out the IO module method of doing this, I'm using a wall wart as you (lee) suggested to trigger a relay on, and then off.
Now, I've tried using the autofeeder code, but I don't know what it is about it, but I just can't get it to work the way I need it too.

In my code, I have a method that sits in loop that checks the orp so that it can decided whether to trigger the ozone on, or off dependent on the values. The way I want to turn the ozone on and off (the ozonator runs all the time) is to call a method that will trigger a relay which a wall wart is plugged into which will then *Press* the switch for 1-2 seconds then release.

Excuse my code from being a mess, I'm throwing stuff together and it's a little unorganized.

Code: Select all


#include <Salinity.h>
#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 <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>
#include <WiFiAlert.h>

 // Custom Menu
 #include <avr/pgmspace.h>
 prog_char menu1_label[] PROGMEM = "Lights On";
 prog_char menu2_label[] PROGMEM = "Feeding Mode";
 prog_char menu3_label[] PROGMEM = "Water Change";
 prog_char menu4_label[] PROGMEM = "ATO Clear";
 prog_char menu5_label[] PROGMEM = "Overheat Clear";
 prog_char menu6_label[] PROGMEM = "PH Calibration";
 prog_char menu7_label[] PROGMEM = "Sal Calibration";
 prog_char menu8_label[] PROGMEM = "ORP Calibration";
 prog_char menu9_label[] PROGMEM = "Date / Time";
 
 // Group the menu entries together
 PROGMEM const char *menu_items[] = {
 menu1_label, menu2_label, menu3_label,
 menu4_label, menu5_label, menu6_label,
 menu7_label, menu8_label, menu9_label
 };

// Define Relay Ports by Name
#define Return             1
#define WaveMakerLeft      2
#define WaveMakerRight     3
#define LED_WhiteBlue      4
#define LED_Supplemental   5
#define LED_Moonlights     6
#define SkimmerPump        7
#define SkimmerVenturi     8

#define OzoneTrigger       Box1_Port1
#define Heater2            Box1_Port2
#define Chiller            Box1_Port3
#define ChillerPump        Box1_Port4
#define SumpLight          Box1_Port5
#define Ozone              Box1_Port6
#define ATO                Box1_Port7
#define Unused	           Box1_Port8


//Define Custom Memory Locations
#define CMem_B_Delay_Ozone        100
#define CMem_B_Delay_Skimmer      101
#define CMem_B_Delay_Chiller      102
#define CMem_I_OrpMin             103
#define CMem_I_OrpMax             104
#define CMem_B_LightsEnabled	  105
#define CMem_B_OzoneRelayDelay	  106

#define CMem_B_ResetMemory        199

void init_memory()
{
  InternalMemory.write(CMem_B_Delay_Ozone,10);
  InternalMemory.write(CMem_B_Delay_Skimmer,1);
  InternalMemory.write(CMem_B_Delay_Chiller,1);
  InternalMemory.write_int(CMem_I_OrpMin,400);
  InternalMemory.write_int(CMem_I_OrpMax,420);
  InternalMemory.write(CMem_B_LightsEnabled,false);

  InternalMemory.write(CMem_B_OzoneRelayDelay,2);

  InternalMemory.write(CMem_B_ResetMemory,true);
}

static boolean bOrpOn;

void setup()
{
  // This must be the first line
  ReefAngel.Init();  //Initialize controller
  ReefAngel.SetTemperatureUnit( Celsius );  // set to Celsius Temperature

  // Ports toggled in Feeding Mode
  ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port3Bit | Port7Bit;
  ReefAngel.FeedingModePortsE[0] = Port4Bit;
  // Ports toggled in Water Change Mode
  ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port5Bit | Port6Bit | Port7Bit | Port8Bit;
  ReefAngel.WaterChangePortsE[0] = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port6Bit | Port7Bit;
  // Ports toggled when Lights On / Off menu entry selected
  ReefAngel.LightsOnPorts = Port4Bit | Port5Bit;
  ReefAngel.LightsOnPortsE[0] = Port5Bit;
  // Ports turned off when Overheat temperature exceeded
  ReefAngel.OverheatShutoffPorts = Port4Bit | Port5Bit | Port6Bit;
  ReefAngel.OverheatShutoffPortsE[0] = Port1Bit | Port2Bit | Port5Bit | Port6Bit;
  // Use T1 probe as temperature and overheat functions
  ReefAngel.TempProbe = T1_PROBE;
  ReefAngel.OverheatProbe = T1_PROBE;


  // Ports that are always on
  ReefAngel.Relay.On( Return );
  ReefAngel.Relay.On( WaveMakerLeft );
  ReefAngel.Relay.On( WaveMakerRight );
  ReefAngel.Relay.On( SkimmerPump );
  ReefAngel.Relay.On( Chiller );
  ReefAngel.Relay.On( ChillerPump );
  //ReefAngel.Relay.On( Heater1 );
  ReefAngel.Relay.On( Heater2 );
  ReefAngel.Relay.On( Chiller );
  ////// Place additional initialization code below here
  bOrpOn = false;

  //RA has been restarted. Set lights enabled memory to off

  ////// Place additional initialization code above here
  //ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items)); // Initialize Menu
  if (InternalMemory.read(CMem_B_ResetMemory))
  {
    init_memory();
    InternalMemory.write(CMem_B_ResetMemory,false);
  }
}

void loop()
{
  //Initialise Relays
  ReefAngel.MoonLights( LED_Moonlights ); 
  ReefAngel.MoonLights( SumpLight );
  ReefAngel.DayLights( LED_WhiteBlue );
  ReefAngel.DayLights( LED_Supplemental );
//ReefAngel.StandardHeater( Heater1 );
//ReefAngel.StandardHeater( Heater2 )
//ReefAngel.StandardFan( ChillerPump );
  ReefAngel.SingleATOLow( ATO );
  ReefAngel.Relay.DelayedOn( Ozone, InternalMemory.read(CMem_B_Delay_Ozone));
  ReefAngel.Relay.DelayedOn( SkimmerVenturi, InternalMemory.read(CMem_B_Delay_Skimmer));
//  ReefAngel.Relay.DelayedOn( Chiller, InternalMemory.read(CMem_B_Delay_Chiller));

  //Check Temp and Control Ports
  //if(InternalMemory.read(temp

  //SetPWM as normal if Lights Mode Off
  if(!InternalMemory.read(CMem_B_LightsEnabled))
  {
	  ReefAngel.PWM.Channel0PWMParabola();
	  ReefAngel.PWM.Channel1PWMParabola();
	  ReefAngel.PWM.Channel2PWMParabola();
	  ReefAngel.PWM.Channel3PWMParabola();
	  ReefAngel.PWM.SetChannel( 4, MoonPhase() );
	  ReefAngel.PWM.SetChannel( 5, MoonPhase() );
  }
  else
  {
	  ReefAngel.PWM.SetChannel(0,80);
	  ReefAngel.PWM.SetChannel(1,100);
	  ReefAngel.PWM.SetChannel(2,100);
	  ReefAngel.PWM.SetChannel(3,100);
  }
  ////// Place your custom code below here

  OrpControl();

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

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

void DrawCustomMain()
{
  int x,y;
  char text[10];
  // Dimming Expansion
  x = 15;
  y = 2;
  for ( int a=0;a<6;a++ )
  {
    if ( a>2 ) x = 75;
    if ( a==3 ) y = 2;
    ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Ch :" );
    ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+12,y,a );
    ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+24,y,ReefAngel.PWM.GetChannelValue(a) );
    y += 10;
  }
  pingSerial();

  // I/O Expansion
  byte bkcolor;
  x = 14;
  y = 32;
  for ( int a=0;a<6;a++ )
  {
    ReefAngel.LCD.DrawCircleOutline( x+(a*20),y,4,COLOR_MEDIUMORCHID );
    if ( ReefAngel.IO.GetChannel(a) ) bkcolor=COLOR_WHITE; 
    else bkcolor=COLOR_GRAY;
    ReefAngel.LCD.FillCircle( x+(a*20),y,2,bkcolor );
  }
  pingSerial();

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

  // Salinity
  ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,16,69, "SAL:" );
  ReefAngel.LCD.DrawSingleMonitor( ReefAngel.Params.Salinity,COLOR_DARKKHAKI,40,69, 10 );    
  pingSerial();

  // ORP
  ReefAngel.LCD.DrawText( COLOR_PALEVIOLETRED,DefaultBGColor,82,69, "ORP:" );
  ReefAngel.LCD.DrawText( COLOR_PALEVIOLETRED,DefaultBGColor,106,69, ReefAngel.Params.ORP );
  pingSerial();

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

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

  // Relay Expansion
  TempRelay = ReefAngel.Relay.RelayDataE[0];
  TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawOutletBox( 12, 103, TempRelay );
  pingSerial();

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


void OrpControl()
{
  int iOrpMax = InternalMemory.read(CMem_I_OrpMax);
  int iOrpMin = InternalMemory.read(CMem_I_OrpMin);
  int iCurrentOrp = ReefAngel.Params.ORP;
  byte bOzoneDelay = InternalMemory.read(CMem_B_Delay_Ozone);
  static WiFiAlert waOrpAlert;

  if(bOrpOn && iCurrentOrp >= iOrpMax)
  {
	//OzoneRelayTrigger();
	//Send alert Orp is Off
	waOrpAlert.Send("Ozone+is+off!+Max+Ozone");
  }
  else if(!bOrpOn && iCurrentOrp <= iOrpMin )
	{
		//Trigger ORP Relay
		//OzoneRelayTrigger();
		
		waOrpAlert.Send("Ozone+is+on.");
	}
}

void OzoneRelayTrigger()
{
	Serial.println("OzoneRelayTrigger");
  static TimerClass afTimer;
  static time_t buttonPress;
  byte orpDelay=InternalMemory.read(CMem_B_OzoneRelayDelay);
    
  if(InternalMemory.read(CMem_B_OzoneRelayDelay)) {
    InternalMemory.write(CMem_B_OzoneRelayDelay,false);
    afTimer.SetInterval(1);
    afTimer.Start();
  }
    
  if(afTimer.IsTriggered())
  {
	  buttonPress=now();
	  if (bOrpOn)
	  {
	  	  bOrpOn = false;
	  }
	  else
	  {
		  bOrpOn = true;
	  }
  }
  
  // Turn on relay for 2 seconds.
  if (now()-buttonPress<2) 
  {
    ReefAngel.Relay.On(OzoneTrigger);
  Serial.println("OzoneTriggerON");
  }
  else
  {
    ReefAngel.Relay.Off(OzoneTrigger);
  Serial.println("OzoneTriggerOFF");
  
  }
}

void Overheat()
{
  //Enter code for overheat
  //Send wifi alert
}


//Menu Code
 /*prog_char menu1_label[] PROGMEM = "Lights On";
 prog_char menu2_label[] PROGMEM = "Feeding Mode";
 prog_char menu3_label[] PROGMEM = "Water Change";
 prog_char menu4_label[] PROGMEM = "ATO Clear";
 prog_char menu5_label[] PROGMEM = "Overheat Clear";
 prog_char menu6_label[] PROGMEM = "PH Calibration";
 prog_char menu7_label[] PROGMEM = "Sal Calibration";
 prog_char menu8_label[] PROGMEM = "ORP Calibration";
 prog_char menu9_label[] PROGMEM = "Date / Time";*/
void MenuEntry1()
{
	//Turn All Lights On
	if(!InternalMemory.read(CMem_B_LightsEnabled))
	{
		//Turn All Lights Relays On (except moons)
		ReefAngel.Relay.Override(LED_WhiteBlue,1);
		ReefAngel.Relay.Override(LED_Supplemental,1);
		ReefAngel.Relay.Override(SumpLight,1);

		InternalMemory.write(CMem_B_LightsEnabled,true);

		//Set PWM to max
		//Might not need to, done in loop
	}
	else
	{
		//Set Lights to default
		ReefAngel.StandardLights(LED_WhiteBlue);
		ReefAngel.StandardLights(LED_Supplemental);
		ReefAngel.MoonLights(SumpLight);

		//Set PWM to normal
		InternalMemory.write(CMem_B_LightsEnabled,false);
	}

}
void MenuEntry2()
{
	//Feeding Mode
	ReefAngel.FeedingModeStart();
}
void MenuEntry3()
{
	//Water Change
	ReefAngel.WaterChangeModeStart();
}
void MenuEntry4()
{
	//ATO Clear
	ReefAngel.ATOClear();
}
void MenuEntry5()
{
	//Overheat Clear
	ReefAngel.OverheatClear();
}
void MenuEntry6()
{
	//PH Calibration
	ReefAngel.SetupCalibratePHExp();
	ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
	//Sal Calibration
	//ReefAngel.SetupCalibrateSalinity();
	//ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;

}
void MenuEntry8()
{
	//ORP Calibration
	
}
void MenuEntry9()
{
	//Date/Time
	ReefAngel.SetupDateTime();
	ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;

}
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Controlling a relay (not relay box)

Post by rimai »

This piece doesn't make sense:

Code: Select all

  if(InternalMemory.read(CMem_B_OzoneRelayDelay)) {
    InternalMemory.write(CMem_B_OzoneRelayDelay,false);
    afTimer.SetInterval(1);
    afTimer.Start();
  }
In the first pass, InternalMemory.read(CMem_B_OzoneRelayDelay) will read 2, assuming you initialized memory.
So the if will result in true and it will assing 0 to that memory location in the next line: InternalMemory.write(CMem_B_OzoneRelayDelay,false);
Then, the if will never be able to return true ever again until you initialize memory again.
I'm not so sure what you were trying to do and why you were saving false (which is the same as zero) to that memory location is the if statement is true.
Roberto.
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

That actually makes sense.
I took that bit of code from the Autofeeder part (it was an early post Lee put up).
I tried to adapt it and I guess I broke it. lol.

My first adaptation of it, i think the Loop() was calling it and it just kept setting now() to the time plus 2 seconds all the time.

So, does that setinterval act like a relay.delay where if its in the loop, it will be a count down? also, with the setinterval is that in minutes or seconds.
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

I don't use the timer class anymore..think its easier with a simple variable to hold the time.

I'll check my current code for you tomorrow and help you pull this off..

Before we jump through hoops you've confirmed this works manually right?
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

That would be awesome Lee

If by manually you mean using the wall wart to trigger the separate relay to act as a switch, then yes. Lol. All the hardware is working perfectly when the relay is triggered for at least 1 second (short bursts don't work). :)
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

I'm stuck. Lol. I tried to get it to work but I think I'm going around in circles. :(
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

Sorry i'll post something later this morning for you to try...
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

I'm assuming the button pressed again turns the ozone off. I'm also assuming that if you are over orpmax you want ozone off and under orpmin you want it on... Also assume kind of like programming a remote control macro that relay off on the ozone followed by relay on for one second on the button press will turn it on... Correct me if I'm off on anything...this is a bit trickier than I expected but no worries...
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

Ok so this was based on the assumptions above. Your OrpControl function will determine if bOrpOn is true or false and then call OzoneRelayTrigger(). If bOrpOn is false it will power off the Ozone port (don't want an out of sync condition...safer to turn off the ozone relay completely...) if bOrpOn is true and the ozone relay is off (so it should only happen once...) it will turn on the ozone port and assign now() to buttonPress. After that it will wait bOzoneDelay seconds (make sure to set this back to non-zero based on your earlier code that was changing it...) then turn on the wall wart on for two seconds. When orp gets over the max, bOrpOn will be false and the trigger function will turn off the ozone again. The trigger relay should be off by default except during the narrow window between the orp delay and orp delay + 2.

Code: Select all

void OrpControl()
{
  int iOrpMax = InternalMemory.read(CMem_I_OrpMax);
  int iOrpMin = InternalMemory.read(CMem_I_OrpMin);
  int iCurrentOrp = ReefAngel.Params.ORP;
  byte bOzoneDelay = InternalMemory.read(CMem_B_Delay_Ozone);
  static WiFiAlert waOrpAlert;

  if(bOrpOn && iCurrentOrp >= iOrpMax)
  {
    //Send alert Orp is Off
    waOrpAlert.Send("Ozone+is+off!+Max+Ozone");
    bOrpOn=false;
  }
  else if(!bOrpOn && iCurrentOrp <= iOrpMin )
  {
    bOrpOn=true;
    waOrpAlert.Send("Ozone+is+on.");
  }

  // Trigger ORP Relay based on bOrpOn global variable
  OzoneRelayTrigger();
}

void OzoneRelayTrigger()
{
  // Serial.println("OzoneRelayTrigger");
  static time_t buttonPress;
  
  // wait some seconds for ozone to turn on before hitting button
  byte orpDelay=InternalMemory.read(CMem_B_OzoneRelayDelay);
    
  // turn on Ozone then trigger button press if ozone is needed
  if (bOrpOn && !ReefAngel.Relay.Status(Ozone) {
    ReefAngel.Relay.On(Ozone);
    buttonPress=now();
  }
  
  // turn off ozone if not needed
  if (!bOrpOn) ReefAngel.Relay.Off(Ozone);
    
  // Turn on relay for 2 seconds but wait for orpDelay
  if ((now()-buttonPress>orpDelay) && (now()-buttonPress<orpDelay+2)) 
  {
    ReefAngel.Relay.On(OzoneTrigger);
    Serial.println("OzoneTriggerON");
  }
  else
  {
    ReefAngel.Relay.Off(OzoneTrigger);
    Serial.println("OzoneTriggerOFF");
  }
}
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

Your assumptions were spot on! Thanks heaps lee, I finally had a chance to upload my program and it works perfectly!
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

:( It did work (I'm fairly sure), but now when I go to fully use it and put the Ozoneator (Box1_Port6) actually plugged in (been breaking in my orp probe so I didn't want it on during inaccurate readings), I find its not working properly....

What seems to be happening is, the ozone relay trigger (Box1_Port1) is working perfectly as it should be, on at startup of the RA for about 3 seconds or so, then off, but the actual ozoneator is only turning on for a split second during the period, then turning off and staying off.

I've gone through the code nearly 100 times now, and I just can't pick whats causing it to be on for only a second and I've tried many different things to try and get it to stay on.

If need be, I don't care if we just get rid of the "delay" of the ozoneator coming on to make things easy. As long as the ozoneator comes on then the relay Trigger is on for about 3-4 seconds this will allow the initial startup of the Ozoneator then the it catching the Relay Trigger.

I'm hoping that makes sense, I think I might be losing it. lol :shock:

Lee or anyone for that matter, are you able to take a look and tell me where I'm going wrong please? Your wisdom is greatly appreciated!

I honestly think I've done something and might have screwed it up, but I can't find what :(

Code: Select all

#include <Salinity.h>
#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 <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>
#include <WiFiAlert.h>

// Custom Menu
#include <avr/pgmspace.h>
prog_char menu1_label[] PROGMEM = "Lights On";
prog_char menu2_label[] PROGMEM = "Feeding Mode";
prog_char menu3_label[] PROGMEM = "Water Change";
prog_char menu4_label[] PROGMEM = "ATO Clear";
prog_char menu5_label[] PROGMEM = "Overheat Clear";
prog_char menu6_label[] PROGMEM = "PH Calibration";
prog_char menu7_label[] PROGMEM = "Sal Calibration";
prog_char menu8_label[] PROGMEM = "ORP Calibration";
prog_char menu9_label[] PROGMEM = "Date / Time";

// Group the menu entries together
PROGMEM const char *menu_items[] = {
	menu1_label, menu2_label, menu3_label,
	menu4_label, menu5_label, menu6_label,
	menu7_label, menu8_label, menu9_label
};

// Define Relay Ports by Name
#define Return             1
#define WaveMakerLeft      2
#define WaveMakerRight     3
#define LED_WhiteBlue      4
#define LED_Supplemental   5
#define LED_Moonlights     6
#define SkimmerPump        7
#define SkimmerVenturi     8

#define OzoneTrigger       Box1_Port1
#define Heater2            Box1_Port2
#define Chiller            Box1_Port3
#define ChillerPump        Box1_Port4
#define SumpLight          Box1_Port5
#define Ozone              Box1_Port6
#define ATO                Box1_Port7
#define Unused	           Box1_Port8


//Define Custom Memory Locations
#define CMem_B_Delay_Ozone        100
#define CMem_B_Delay_Skimmer      101
#define CMem_B_Delay_Chiller      102
#define CMem_I_OrpMin             103
#define CMem_I_OrpMax             104
#define CMem_B_LightsEnabled	  105
#define CMem_B_OzoneRelayDelay	  106

#define CMem_B_ResetMemory        199

void init_memory()
{
	InternalMemory.write(CMem_B_Delay_Ozone,10);
	InternalMemory.write(CMem_B_Delay_Skimmer,1);
	InternalMemory.write(CMem_B_Delay_Chiller,1);
	InternalMemory.write_int(CMem_I_OrpMin,400);
	InternalMemory.write_int(CMem_I_OrpMax,420);
	InternalMemory.write(CMem_B_LightsEnabled,false);
	InternalMemory.write(CMem_B_OzoneRelayDelay,3);

	InternalMemory.write(CMem_B_ResetMemory,true);
}

static boolean bOrpOn;

void setup()
{
	// This must be the first line
	ReefAngel.Init();  //Initialize controller
	ReefAngel.SetTemperatureUnit( Celsius );  // set to Celsius Temperature

	// Ports toggled in Feeding Mode
	ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port3Bit | Port7Bit;
	ReefAngel.FeedingModePortsE[0] = Port4Bit;
	// Ports toggled in Water Change Mode
	ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port5Bit | Port6Bit | Port7Bit | Port8Bit;
	ReefAngel.WaterChangePortsE[0] = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port6Bit | Port7Bit;
	// Ports toggled when Lights On / Off menu entry selected
	ReefAngel.LightsOnPorts = Port4Bit | Port5Bit;
	ReefAngel.LightsOnPortsE[0] = Port5Bit;
	// Ports turned off when Overheat temperature exceeded
	ReefAngel.OverheatShutoffPorts = Port4Bit | Port5Bit | Port6Bit;
	ReefAngel.OverheatShutoffPortsE[0] = Port1Bit | Port2Bit | Port5Bit | Port6Bit;
	// Use T1 probe as temperature and overheat functions
	ReefAngel.TempProbe = T1_PROBE;
	ReefAngel.OverheatProbe = T1_PROBE;


	// Ports that are always on
	ReefAngel.Relay.On( Return );
	ReefAngel.Relay.On( WaveMakerLeft );
	ReefAngel.Relay.On( WaveMakerRight );
	ReefAngel.Relay.On( SkimmerPump );
	ReefAngel.Relay.On( Chiller );
	ReefAngel.Relay.On( ChillerPump );
	ReefAngel.Relay.On( Heater2 );
	////// Place additional initialization code below here
	bOrpOn = false;

	//RA has been restarted. Set lights enabled memory to off

	////// Place additional initialization code above here
	ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items)); // Initialize Menu
	if (InternalMemory.read(CMem_B_ResetMemory))
	{
		init_memory();
		InternalMemory.write(CMem_B_ResetMemory,false);
	}
}

void loop()
{
	//Initialise Relays
	ReefAngel.MoonLights( LED_Moonlights ); 
	ReefAngel.MoonLights( SumpLight );
	ReefAngel.DayLights( LED_WhiteBlue );
	ReefAngel.DayLights( LED_Supplemental );
	ReefAngel.SingleATOLow( ATO );
	//ReefAngel.Relay.DelayedOn( Ozone, InternalMemory.read(CMem_B_Delay_Ozone));
	ReefAngel.Relay.DelayedOn( SkimmerVenturi, InternalMemory.read(CMem_B_Delay_Skimmer));
	//ReefAngel.Relay.DelayedOn( Chiller, InternalMemory.read(CMem_B_Delay_Chiller));

	////// Place your custom code below here

	OrpControl();			//Checks ORP on orp probe, and enables or disables Ozoneator depending.
	TempControl();			//INACTIVE: Checks Temp and enables and disables heaters and chiller depending.
	LightModeCheck();		//Checks the lights enabled varible then sets lights on or off depending.
	//Overheat();				//INACTIVE: Checks overheat status, and acts occordingly.
	//HourlyMaintenance();	//INACTIVE: Performs hourly Maintenance

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

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

void LightModeCheck()
{
	//Check to see if lights mode is enabled, if so, set relays
	if(!InternalMemory.read(CMem_B_LightsEnabled))
	{
		//Set light relays to normal
		ReefAngel.MoonLights( SumpLight );
		ReefAngel.DayLights( LED_WhiteBlue );
		ReefAngel.DayLights( LED_Supplemental );
		//Set PWM to normal
		ReefAngel.PWM.Channel0PWMParabola();
		ReefAngel.PWM.Channel1PWMParabola();
		ReefAngel.PWM.Channel2PWMParabola();
		ReefAngel.PWM.Channel3PWMParabola();
		ReefAngel.PWM.SetChannel( 4, MoonPhase() );
		ReefAngel.PWM.SetChannel( 5, MoonPhase() );
	}
	else
	{
		//Turn light relays on
		ReefAngel.Relay.On( SumpLight );
		ReefAngel.Relay.On( LED_WhiteBlue );
		ReefAngel.Relay.On( LED_Supplemental );
		//Set PWM to normals
		ReefAngel.PWM.SetChannel(0,80);
		ReefAngel.PWM.SetChannel(1,100);
		ReefAngel.PWM.SetChannel(2,100);
		ReefAngel.PWM.SetChannel(3,100);
	}
}

void DrawCustomMain()
{
	int x,y;
	char text[10];
	// Dimming Expansion
	x = 15;
	y = 2;
	for ( int a=0;a<6;a++ )
	{
		if ( a>2 ) x = 75;
		if ( a==3 ) y = 2;
		ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Ch :" );
		ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+12,y,a );
		ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+24,y,ReefAngel.PWM.GetChannelValue(a) );
		y += 10;
	}
	pingSerial();

	// I/O Expansion
	byte bkcolor;
	x = 14;
	y = 32;
	for ( int a=0;a<6;a++ )
	{
		ReefAngel.LCD.DrawCircleOutline( x+(a*20),y,4,COLOR_MEDIUMORCHID );
		if ( ReefAngel.IO.GetChannel(a) ) bkcolor=COLOR_WHITE; 
		else bkcolor=COLOR_GRAY;
		ReefAngel.LCD.FillCircle( x+(a*20),y,2,bkcolor );
	}
	pingSerial();

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

	// Salinity
	ReefAngel.LCD.DrawText( COLOR_DARKKHAKI,DefaultBGColor,16,69, "SAL:" );
	ReefAngel.LCD.DrawSingleMonitor( ReefAngel.Params.Salinity,COLOR_DARKKHAKI,40,69, 10 );    
	pingSerial();

	// ORP
	ReefAngel.LCD.DrawText( COLOR_PALEVIOLETRED,DefaultBGColor,82,69, "ORP:" );
	ReefAngel.LCD.DrawText( COLOR_PALEVIOLETRED,DefaultBGColor,106,69, ReefAngel.Params.ORP );
	pingSerial();

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

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

	// Relay Expansion
	TempRelay = ReefAngel.Relay.RelayDataE[0];
	TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
	TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
	ReefAngel.LCD.DrawOutletBox( 12, 103, TempRelay );
	pingSerial();

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

void DrawCustomGraph()
{
}

void HourlyMaintenance()
{
	//Check to see if NOW is an hour.
	if (now()%SECS_PER_HOUR == 0)
	{
		//Perform Cleanup/Checks for out of sync
	}

}


void OrpControl()
{
	int iOrpMax = InternalMemory.read(CMem_I_OrpMax);
	int iOrpMin = InternalMemory.read(CMem_I_OrpMin);
	int iCurrentOrp = ReefAngel.Params.ORP;
	byte bOzoneDelay = InternalMemory.read(CMem_B_Delay_Ozone);
	static WiFiAlert waOrpAlert;

	if(bOrpOn && iCurrentOrp >= iOrpMax)
	{
		//Send alert Orp is Off
		waOrpAlert.Send("Ozone+is+off!+Max+Ozone");
		bOrpOn=false;
	}
	else if(!bOrpOn && iCurrentOrp <= iOrpMin )
	{
		bOrpOn=true;
		waOrpAlert.Send("Ozone+is+on.");
	}

	// Trigger ORP Relay based on bOrpOn global variable
	OzoneRelayTrigger();
}

void OzoneRelayTrigger()
{
	// Serial.println("OzoneRelayTrigger");
	static time_t buttonPress;

	// wait some seconds for ozone to turn on before hitting button
	byte orpDelay=InternalMemory.read(CMem_B_OzoneRelayDelay);

	// turn on Ozone then trigger button press if ozone is needed
	if (bOrpOn && !ReefAngel.Relay.Status(Ozone)) {
		ReefAngel.Relay.On(Ozone);
		buttonPress=now();
	}

	// turn off ozone if not needed
	if (!bOrpOn) ReefAngel.Relay.Off(Ozone);

	// Turn on relay for 2 seconds but wait for orpDelay
	if ((now()-buttonPress>orpDelay) && (now()-buttonPress<orpDelay+2)) 
	{
		ReefAngel.Relay.On(OzoneTrigger);
		Serial.println("OzoneTriggerON");
	}
	else
	{
		ReefAngel.Relay.Off(OzoneTrigger);
		Serial.println("OzoneTriggerOFF");
	}
}

void TempControl()
{
	if ((ReefAngel.Params.Temp[T1_PROBE] >= InternalMemory.read_int(Mem_I_ChillerTempOn)) && (ReefAngel.Params.Temp[T1_PROBE] <= InternalMemory.read_int(Mem_I_ChillerTempOff)))
	{
		//Turn on Chiller Ports
	}
	else
	{
		//Turn off chiller ports

	}
}

void Overheat()
{
	//Enter code for overheat
	//Send wifi alert
}

void LightsEnable()
{
	//Turn All Lights On
	if(!InternalMemory.read(CMem_B_LightsEnabled))
	{
		//Set Lights Enabled Item to true so lights are on
		InternalMemory.write(CMem_B_LightsEnabled,true);
	}
	else
	{
		//Set Lights Disabled Item to true so lights are normal
		InternalMemory.write(CMem_B_LightsEnabled,false);
	}
}

//Menu Entry Block
void MenuEntry1()
{
	//Turn All Lights On

	//NOTE: Merged code from here to LightsEnable method
	LightsEnable();
}
void MenuEntry2()
{
	//Feeding Mode
	ReefAngel.FeedingModeStart();
}
void MenuEntry3()
{
	//Water Change
	LightsEnable();
	ReefAngel.WaterChangeModeStart();
}
void MenuEntry4()
{
	//ATO Clear
	ReefAngel.ATOClear();
}
void MenuEntry5()
{
	//Overheat Clear
	ReefAngel.OverheatClear();
}
void MenuEntry6()
{
	//PH Calibration
	ReefAngel.SetupCalibratePHExp();
	ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
	//Sal Calibration
	ReefAngel.SetupCalibrateSalinity();
	ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;

}
void MenuEntry8()
{
	//ORP Calibration
	ReefAngel.SetupCalibrateORP();
}
void MenuEntry9()
{
	//Date/Time
	ReefAngel.SetupDateTime();
	ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;

}
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

The ozone on and off is controlled by the bOrpOn variable. This is based on the orpmin and orpmax that you set. It's controlled independently from the relay trigger and delay... I would start with confirming your memory variables are set properly and then also add some serial.println calls showing the value of bOrpOn so you can see if that is what's expected or not. The code looks ok, doesn't look like you changed anything functional. But I would start with the debug to see what's happening with bOrpOn...
egadgetjnr
Posts: 54
Joined: Wed Jul 18, 2012 1:32 pm

Re: Controlling a relay (not relay box)

Post by egadgetjnr »

I might give that a go. Just play around a bit more to get it to tell me what's going on.
I keep getting the odd random email a couple of times a day telling me ORP is on the sometimes off when it hasn't change to be high enough to turn of. It's weird
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Controlling a relay (not relay box)

Post by lnevo »

Sensors jitter. Thats actually a problem in your code a bit...need to measure that its been in low orp or high orp long enough to be real...it could be messing with the actual usage enough to be a problem.
Post Reply