Tunze Control

Basic / Standard Reef Angel hardware
Post Reply
discocarp
Posts: 21
Joined: Fri Oct 05, 2012 9:13 am

Tunze Control

Post by discocarp »

I have a pair of Tunze Stream 6105's. I will likely do something more complex later, but this is what I put together for now. I found rimai's tunze pulsing functions but I wanted a little more, so I wrote a quick sine wave function to control them. Basically it does this:

Image

Then I added on the pulsing code to pulse from the minimum up to the sine wave flow.

Code: Select all

//*** Define only one mode ***
//#define TUNZE_MODE_SINE // sine wave, no pulse
//#define TUNZE_MODE_LONG // no sine wave, long pulse
//#define TUNZE_MODE_SHORT // no sine wave, short pulse
//#define TUNZE_MODE_LONGSINE // sine wave, long pulse
#define TUNZE_MODE_SHORTSINE // sine wave, short pulse


#define TUNZE_MIN 30
#define TUNZE_MAX 75

#define TUNZE_SINE_SEC 23400
#define TUNZE_SINE_SYNC false

#define TUNZE_LONGPULSE_SEC 2
#define TUNZE_LONGPULSE_SYNC true

#define TUNZE_SHORTPULSE_MS 500
#define TUNZE_SHORTPULSE_SYNC true

//PulseMinSpeed - % for minimal speed
//PulseMaxSpeed - % for maximum speed
//PulseDuration - Duration (milliseconds) in which each pulse will be held. The pump will stay at minimal speed for PulseDuration and will stay at maximum speed for PulseDuration.
//PulseSync - true if you want to sync pumps to same cycle. one false and one true if you want to anti-sync pumps.
byte TunzeShortPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  byte tspeed=0;
  PulseMinSpeed=constrain(PulseMinSpeed,30,100);
  PulseMaxSpeed=constrain(PulseMaxSpeed,30,100);
  tspeed=(millis()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
  if (PulseSync)
    return tspeed;
  else
    return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}

//PulseMinSpeed - % for minimal speed
//PulseMaxSpeed - % for maximum speed
//PulseDuration - Duration (seconds) in which each pulse will be held. The pump will stay at minimal speed for PulseDuration and will stay at maximum speed for PulseDuration.
//PulseSync - true if you want to sync pumps to same cycle. one false and one true if you want to anti-sync pumps.
byte TunzeLongPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  byte tspeed=0;
  PulseMinSpeed=constrain(PulseMinSpeed,30,100);
  PulseMaxSpeed=constrain(PulseMaxSpeed,30,100);
  tspeed=(now()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
  if (PulseSync)
    return tspeed;
  else
    return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}


byte TunzeSineWave(boolean isleftpump, byte minspeed, byte maxspeed, int period_sec) {
  double x,y;

  x=double(now()%(period_sec));
  x/=period_sec;
  x*=2.0*PI;
  if (!isleftpump) x+=PI; // shift the sine wave for the right pump 

  y=sin(x);// y is now between -1 and 1
  y+=1.0; // y is now between 0 and 2
  y/=2.0; // y is now between 0 and 1  
  
  // now compute the tunze speed
  y*=double(maxspeed-minspeed);
  y+=double(minspeed); 
  
  y+=0.5; // for proper rounding
  
  // y is now between minspeed and maxspeed, constrain for safety  
  return constrain(byte(y),30,100); 
}


void RunTunzes() {
  
#ifdef TUNZE_MODE_SINE
    ReefAngel.PWM.SetDaylight(TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC)); // left tunze
    ReefAngel.PWM.SetActinic(TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC)); // right tunze
#endif

#ifdef TUNZE_MODE_LONG
    ReefAngel.PWM.SetDaylight(TunzeLongPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_LONGPULSE_SEC,true)); // left tunze
    ReefAngel.PWM.SetActinic(TunzeLongPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_LONGPULSE_SEC,TUNZE_LONGPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_SHORT
    ReefAngel.PWM.SetDaylight(TunzeShortPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_SHORTPULSE_MS,true)); // left tunze
    ReefAngel.PWM.SetActinic(TunzeShortPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_SHORTPULSE_MS,TUNZE_SHORTPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_LONGSINE
    ReefAngel.PWM.SetDaylight(TunzeLongPulse(TUNZE_MIN,TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_LONGPULSE_SEC,true)); // left tunze
    ReefAngel.PWM.SetActinic(TunzeLongPulse(TUNZE_MIN,TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_LONGPULSE_SEC,TUNZE_LONGPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_SHORTSINE
    ReefAngel.PWM.SetDaylight(TunzeShortPulse(TUNZE_MIN,TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_SHORTPULSE_MS,true)); // left tunze
    ReefAngel.PWM.SetActinic(TunzeShortPulse(TUNZE_MIN,TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_SHORTPULSE_MS,TUNZE_SHORTPULSE_SYNC)); // right tunze
#endif

}


I just set up the #defines and call RunTunzes from in the loop.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Tunze Control

Post by rimai »

Nice :)
Roberto.
discocarp
Posts: 21
Joined: Fri Oct 05, 2012 9:13 am

Re: Tunze Control

Post by discocarp »

The Reef Angel officially earned its cabinet space, as I pulled out the tunze 7095 controller. :)
mason dixon
Posts: 26
Joined: Mon May 14, 2012 6:19 am

Re: Tunze Control

Post by mason dixon »

Discocarp, how are you liking this code so far? I have 2 6095's that I'd like to control with this same code, I'm still green to putting code together with my RA, can you put it in the right places for me? Thanks

Here's my code so far:

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 <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>

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


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


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port7Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port7Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port1Bit | Port2Bit | Port3Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port6Bit | Port8Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 790 );


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

    ////// Place additional initialization code below here
    

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

void loop()
{
    ReefAngel.StandardLights( Port1,9,0,20,0 );
    ReefAngel.StandardLights( Port2,9,0,20,0 );
    ReefAngel.StandardLights( Port3,8,0,23,0 );
    ReefAngel.PWM.SetChannel( 0, PWMParabola(9,0,20,0,15,100,15) );
    ReefAngel.PWM.SetChannel( 1, PWMParabola(9,0,20,0,15,100,15) );
    ReefAngel.PWM.SetChannel( 2, PWMParabola(9,0,20,0,15,100,15) );
    ReefAngel.PWM.SetChannel( 3, PWMParabola(6,0,23,0,15,100,15) );
    ReefAngel.PWM.SetChannel( 4, PWMParabola(9,0,20,0,15,100,15) );
    ReefAngel.PWM.SetChannel( 5, PWMSlope(20,0,10,0,15,70,20,15) );
    ////// Place your custom code below here
    

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

    // This should always be the last line
    ReefAngel.Portal( "Mason Dixon" );
    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();

    // 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();

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

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

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

void DrawCustomGraph()
{
}
carlii
Posts: 91
Joined: Sat Mar 17, 2012 7:22 pm

Re: Tunze Control

Post by carlii »

So how woudl I add this function to my Reef Angel? I have a pair of Tunze 6055s.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Tunze Control

Post by rimai »

Which one do you want to use?
Roberto.
carlii
Posts: 91
Joined: Sat Mar 17, 2012 7:22 pm

Re: Tunze Control

Post by carlii »

I guess my challenge is translating the code above to work on ports 0 and 1 on the analogue dimming expansion. I don't know how to program my RA + unit to see the expansion or use it.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Tunze Control

Post by rimai »

There are basically 5 waveforms that discocarp created.
TUNZE_MODE_SINE // sine wave, no pulse
TUNZE_MODE_LONG // no sine wave, long pulse
TUNZE_MODE_SHORT // no sine wave, short pulse
TUNZE_MODE_LONGSINE // sine wave, long pulse
TUNZE_MODE_SHORTSINE // sine wave, short pulse

Which mode do you want to run?
Roberto.
jayclaire
Posts: 24
Joined: Tue Jan 29, 2013 11:15 am

Re: Tunze Control

Post by jayclaire »

I'd like to try TUNZE_MODE_SINE // sine wave, no pulse
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Tunze Control

Post by rimai »

Ok, what you do is copy the whole thing posted in that post and paste it at the end of your code after the last }
Change the code you pasted to whichever function you want to use.
Please note that only one mode should be uncommented.

Code: Select all

//*** Define only one mode ***
#define TUNZE_MODE_SINE // sine wave, no pulse
//#define TUNZE_MODE_LONG // no sine wave, long pulse
//#define TUNZE_MODE_SHORT // no sine wave, short pulse
//#define TUNZE_MODE_LONGSINE // sine wave, long pulse
//#define TUNZE_MODE_SHORTSINE // sine wave, short pulse
Then, in your loop section, add this:

Code: Select all

RunTunzes();
Roberto.
carlii
Posts: 91
Joined: Sat Mar 17, 2012 7:22 pm

Re: Tunze Control

Post by carlii »

OK I copied and pasted the code, but get an error:

a function defintion is not allowed here before '{' token

Here is my code.

#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>

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


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


void setup()
{
// This must be the first line
ReefAngel.Init(); //Initialize controller
// Ports toggled in Feeding Mode
ReefAngel.FeedingModePorts = Port1Bit | Port8Bit;
ReefAngel.FeedingModePortsE[0] = Port7Bit | Port8Bit;
// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port1Bit |Port5Bit | Port6Bit | Port7Bit | Port8Bit;
ReefAngel.WaterChangePortsE[0] = Port5Bit | Port7Bit | Port8Bit;
// Ports toggled when Lights On / Off menu entry selected
ReefAngel.LightsOnPorts = Port2Bit | Port3Bit | Port4Bit ;
ReefAngel.LightsOnPortsE[0] = 0;
// Ports turned off when Overheat temperature exceeded
ReefAngel.OverheatShutoffPorts = Port2Bit | Port3Bit | Port4Bit;
ReefAngel.OverheatShutoffPortsE[0] = Port5Bit | Port7Bit | Port8Bit;
// Use T1 probe as temperature and overheat functions
ReefAngel.TempProbe = T1_PROBE;
ReefAngel.OverheatProbe = T1_PROBE;

// Setup ATO Port for AI communication
ReefAngel.AI.SetPort( highATOPin );


// Ports that are always on
ReefAngel.Relay.On( Box1_Port8 ); //Return Pump
ReefAngel.Relay.On( Box1_Port6 ); //BioPellet Reactor

////// Place additional initialization code below here

//*** Define only one mode ***
//#define TUNZE_MODE_SINE // sine wave, no pulse
//#define TUNZE_MODE_LONG // no sine wave, long pulse
//#define TUNZE_MODE_SHORT // no sine wave, short pulse
//#define TUNZE_MODE_LONGSINE // sine wave, long pulse
//#define TUNZE_MODE_SHORTSINE // sine wave, short pulse


#define TUNZE_MIN 30
#define TUNZE_MAX 75

#define TUNZE_SINE_SEC 23400
#define TUNZE_SINE_SYNC false

#define TUNZE_LONGPULSE_SEC 2
#define TUNZE_LONGPULSE_SYNC true

#define TUNZE_SHORTPULSE_MS 500
#define TUNZE_SHORTPULSE_SYNC true

//PulseMinSpeed - % for minimal speed
//PulseMaxSpeed - % for maximum speed
//PulseDuration - Duration (milliseconds) in which each pulse will be held. The pump will stay at minimal speed for PulseDuration and will stay at maximum speed for PulseDuration.
//PulseSync - true if you want to sync pumps to same cycle. one false and one true if you want to anti-sync pumps.
byte TunzeShortPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
byte tspeed=0;
PulseMinSpeed=constrain(PulseMinSpeed,30,100);
PulseMaxSpeed=constrain(PulseMaxSpeed,30,100);
tspeed=(millis()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
if (PulseSync)
return tspeed;
else
return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}

//PulseMinSpeed - % for minimal speed
//PulseMaxSpeed - % for maximum speed
//PulseDuration - Duration (seconds) in which each pulse will be held. The pump will stay at minimal speed for PulseDuration and will stay at maximum speed for PulseDuration.
//PulseSync - true if you want to sync pumps to same cycle. one false and one true if you want to anti-sync pumps.
byte TunzeLongPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
byte tspeed=0;
PulseMinSpeed=constrain(PulseMinSpeed,30,100);
PulseMaxSpeed=constrain(PulseMaxSpeed,30,100);
tspeed=(now()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
if (PulseSync)
return tspeed;
else
return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}


byte TunzeSineWave(boolean isleftpump, byte minspeed, byte maxspeed, int period_sec) {
double x,y;

x=double(now()%(period_sec));
x/=period_sec;
x*=2.0*PI;
if (!isleftpump) x+=PI; // shift the sine wave for the right pump

y=sin(x);// y is now between -1 and 1
y+=1.0; // y is now between 0 and 2
y/=2.0; // y is now between 0 and 1

// now compute the tunze speed
y*=double(maxspeed-minspeed);
y+=double(minspeed);

y+=0.5; // for proper rounding

// y is now between minspeed and maxspeed, constrain for safety
return constrain(byte(y),30,100);
}


void RunTunzes() {

#ifdef TUNZE_MODE_SINE
ReefAngel.PWM.SetDaylight(TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC)); // left tunze
ReefAngel.PWM.SetActinic(TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC)); // right tunze
#endif

#ifdef TUNZE_MODE_LONG
ReefAngel.PWM.SetDaylight(TunzeLongPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_LONGPULSE_SEC,true)); // left tunze
ReefAngel.PWM.SetActinic(TunzeLongPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_LONGPULSE_SEC,TUNZE_LONGPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_SHORT
ReefAngel.PWM.SetDaylight(TunzeShortPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_SHORTPULSE_MS,true)); // left tunze
ReefAngel.PWM.SetActinic(TunzeShortPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_SHORTPULSE_MS,TUNZE_SHORTPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_LONGSINE
ReefAngel.PWM.SetDaylight(TunzeLongPulse(TUNZE_MIN,TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_LONGPULSE_SEC,true)); // left tunze
ReefAngel.PWM.SetActinic(TunzeLongPulse(TUNZE_MIN,TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_LONGPULSE_SEC,TUNZE_LONGPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_SHORTSINE
ReefAngel.PWM.SetDaylight(TunzeShortPulse(TUNZE_MIN,TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_SHORTPULSE_MS,true)); // left tunze
ReefAngel.PWM.SetActinic(TunzeShortPulse(TUNZE_MIN,TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_SHORTPULSE_MS,TUNZE_SHORTPULSE_SYNC)); // right tunze
#endif

}



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

void loop()
{
ReefAngel.WaterLevelATO(Port1,1800,45,55);
ReefAngel.DayLights( Port2 );
ReefAngel.DayLights( Port3 );
ReefAngel.DayLights( Port4 );
ReefAngel.StandardFan( Port8 );
ReefAngel.DosingPumpRepeat1( Box1_Port1 );
ReefAngel.DosingPumpRepeat2( Box1_Port2 );
ReefAngel.StandardFan( Box1_Port4 );
ReefAngel.StandardLights( Box1_Port3,20,0,6,0);
ReefAngel.StandardHeater( Box1_Port7 );
ReefAngel.StandardHeater( Box1_Port5 );
ReefAngel.Relay.On(Port5);
ReefAngel.Relay.On(Port6);
ReefAngel.AI.ChannelWhiteSlope();
ReefAngel.AI.ChannelBlueSlope();
ReefAngel.AI.ChannelRoyalBlueSlope();
////// Place your custom code below here

RunTunzes();
///skimmer float switch

if (ReefAngel.LowATO.IsActive()) ReefAngel.Relay.On(Port7); else ReefAngel.Relay.Off(Port7);

// moonlight function // 6p to 8p
if ( (hour() >= 18) && (hour() < 20) ) ReefAngel.Relay.On( Port3 );

//lighting fonction with night mode
if ( (hour() >= 18) || (hour() < 10) ) // from 7p - 10a
{
ReefAngel.AI.SetChannel(White,0);
ReefAngel.AI.SetChannel(Blue,0);
ReefAngel.AI.SetChannel(RoyalBlue,MoonPhase()*.06);
}
else
// during the day
if ( (hour() >= 10) || (hour() <= 18) ) // from 10a - 6p
{



}








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

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

byte x,y;
char text[10];

void DrawCustomMain()
{
// the graph is drawn/updated when we exit the main menu &
// when the parameters are saved
ReefAngel.LCD.Clear(BtnActiveColor,5,0,127,11);
ReefAngel.LCD.DrawText(DefaultBGColor,BtnActiveColor,30,3,"My Reef Angel");
ReefAngel.LCD.DrawDate(6, 122);
pingSerial();
#if defined DisplayLEDPWM && ! defined RemoveAllLights
ReefAngel.LCD.DrawMonitor(15, 15, ReefAngel.Params);
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
ReefAngel.LCD.DrawMonitor(15, 15, ReefAngel.Params);
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
pingSerial();
ReefAngel.LCD.Clear(DefaultFGColor,5,52,127,52);
ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,15,55,"Aqua Illumination");
x=15;
y=68;
ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"White:");
ConvertNumToString(text, ReefAngel.AI.GetChannel(White), 1);
strcat(text," ");
ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x+74,y,text);
y+=10;
pingSerial();
ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Blue:");
ConvertNumToString(text, ReefAngel.AI.GetChannel(Blue), 1);
strcat(text," ");
ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x+74,y,text);
y+=10;
pingSerial();
ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Royal Blue:");
ConvertNumToString(text, ReefAngel.AI.GetChannel(RoyalBlue), 1);
strcat(text," ");
ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x+74,y,text);
y+=10;
pingSerial();
byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 97, TempRelay);
pingSerial();
TempRelay = ReefAngel.Relay.RelayDataE[0];
TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
ReefAngel.LCD.DrawOutletBox(12, 109, TempRelay);

// Water Level
ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,75,36, "WL:" );
ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,99,36, ReefAngel.WaterLevel.GetLevel() );
pingSerial();
}

void DrawCustomGraph()
{
}
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Tunze Control

Post by rimai »

Almost...
The pasted piece had to be all the way at the end of your code.

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <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>

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


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


void setup()
{
  // This must be the first line
  ReefAngel.Init(); //Initialize controller
  // Ports toggled in Feeding Mode
  ReefAngel.FeedingModePorts = Port1Bit | Port8Bit;
  ReefAngel.FeedingModePortsE[0] = Port7Bit | Port8Bit;
  // Ports toggled in Water Change Mode
  ReefAngel.WaterChangePorts = Port1Bit |Port5Bit | Port6Bit | Port7Bit | Port8Bit;
  ReefAngel.WaterChangePortsE[0] = Port5Bit | Port7Bit | Port8Bit;
  // Ports toggled when Lights On / Off menu entry selected
  ReefAngel.LightsOnPorts = Port2Bit | Port3Bit | Port4Bit ;
  ReefAngel.LightsOnPortsE[0] = 0;
  // Ports turned off when Overheat temperature exceeded
  ReefAngel.OverheatShutoffPorts = Port2Bit | Port3Bit | Port4Bit;
  ReefAngel.OverheatShutoffPortsE[0] = Port5Bit | Port7Bit | Port8Bit;
  // Use T1 probe as temperature and overheat functions
  ReefAngel.TempProbe = T1_PROBE;
  ReefAngel.OverheatProbe = T1_PROBE;

  // Setup ATO Port for AI communication
  ReefAngel.AI.SetPort( highATOPin );


  // Ports that are always on
  ReefAngel.Relay.On( Box1_Port8 ); //Return Pump
  ReefAngel.Relay.On( Box1_Port6 ); //BioPellet Reactor

  ////// Place additional initialization code below here


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

void loop()
{
  ReefAngel.WaterLevelATO(Port1,1800,45,55);
  ReefAngel.DayLights( Port2 );
  ReefAngel.DayLights( Port3 );
  ReefAngel.DayLights( Port4 );
  ReefAngel.StandardFan( Port8 );
  ReefAngel.DosingPumpRepeat1( Box1_Port1 );
  ReefAngel.DosingPumpRepeat2( Box1_Port2 );
  ReefAngel.StandardFan( Box1_Port4 );
  ReefAngel.StandardLights( Box1_Port3,20,0,6,0);
  ReefAngel.StandardHeater( Box1_Port7 );
  ReefAngel.StandardHeater( Box1_Port5 );
  ReefAngel.Relay.On(Port5);
  ReefAngel.Relay.On(Port6);
  ReefAngel.AI.ChannelWhiteSlope();
  ReefAngel.AI.ChannelBlueSlope();
  ReefAngel.AI.ChannelRoyalBlueSlope();
  ////// Place your custom code below here

    RunTunzes();
  ///skimmer float switch

  if (ReefAngel.LowATO.IsActive()) ReefAngel.Relay.On(Port7); 
  else ReefAngel.Relay.Off(Port7); 

  // moonlight function // 6p to 8p
  if ( (hour() >= 18) && (hour() < 20) ) ReefAngel.Relay.On( Port3 );

  //lighting fonction with night mode 
  if ( (hour() >= 18) || (hour() < 10) ) // from 7p - 10a
  { 
    ReefAngel.AI.SetChannel(White,0);
    ReefAngel.AI.SetChannel(Blue,0);
    ReefAngel.AI.SetChannel(RoyalBlue,MoonPhase()*.06);
  }
  else
    // during the day
    if ( (hour() >= 10) || (hour() <= 18) ) // from 10a - 6p
    {



    } 








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

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

byte x,y;
char text[10];

void DrawCustomMain()
{
  // the graph is drawn/updated when we exit the main menu &
  // when the parameters are saved
  ReefAngel.LCD.Clear(BtnActiveColor,5,0,127,11);
  ReefAngel.LCD.DrawText(DefaultBGColor,BtnActiveColor,30,3,"My Reef Angel");
  ReefAngel.LCD.DrawDate(6, 122);
  pingSerial();
#if defined DisplayLEDPWM && ! defined RemoveAllLights
  ReefAngel.LCD.DrawMonitor(15, 15, ReefAngel.Params,
  ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue());
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
  ReefAngel.LCD.DrawMonitor(15, 15, ReefAngel.Params);
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
  pingSerial();
  ReefAngel.LCD.Clear(DefaultFGColor,5,52,127,52);
  ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,15,55,"Aqua Illumination");
  x=15;
  y=68;
  ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"White:");
  ConvertNumToString(text, ReefAngel.AI.GetChannel(White), 1);
  strcat(text," ");
  ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x+74,y,text);
  y+=10;
  pingSerial();
  ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Blue:");
  ConvertNumToString(text, ReefAngel.AI.GetChannel(Blue), 1);
  strcat(text," ");
  ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x+74,y,text);
  y+=10;
  pingSerial();
  ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Royal Blue:");
  ConvertNumToString(text, ReefAngel.AI.GetChannel(RoyalBlue), 1);
  strcat(text," ");
  ReefAngel.LCD.DrawText(COLOR_DARKGOLDENROD,DefaultBGColor,x+74,y,text);
  y+=10;
  pingSerial();
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 97, TempRelay);
  pingSerial();
  TempRelay = ReefAngel.Relay.RelayDataE[0];
  TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawOutletBox(12, 109, TempRelay);

  // Water Level
  ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,75,36, "WL:" );
  ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,99,36, ReefAngel.WaterLevel.GetLevel() );
  pingSerial();
}

void DrawCustomGraph()
{
}

//*** Define only one mode ***
//#define TUNZE_MODE_SINE // sine wave, no pulse
//#define TUNZE_MODE_LONG // no sine wave, long pulse
//#define TUNZE_MODE_SHORT // no sine wave, short pulse
//#define TUNZE_MODE_LONGSINE // sine wave, long pulse
//#define TUNZE_MODE_SHORTSINE // sine wave, short pulse


#define TUNZE_MIN 30
#define TUNZE_MAX 75

#define TUNZE_SINE_SEC 23400
#define TUNZE_SINE_SYNC false

#define TUNZE_LONGPULSE_SEC 2
#define TUNZE_LONGPULSE_SYNC true

#define TUNZE_SHORTPULSE_MS 500
#define TUNZE_SHORTPULSE_SYNC true

//PulseMinSpeed - % for minimal speed
//PulseMaxSpeed - % for maximum speed
//PulseDuration - Duration (milliseconds) in which each pulse will be held. The pump will stay at minimal speed for PulseDuration and will stay at maximum speed for PulseDuration.
//PulseSync - true if you want to sync pumps to same cycle. one false and one true if you want to anti-sync pumps.
byte TunzeShortPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  byte tspeed=0;
  PulseMinSpeed=constrain(PulseMinSpeed,30,100);
  PulseMaxSpeed=constrain(PulseMaxSpeed,30,100);
  tspeed=(millis()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
  if (PulseSync)
    return tspeed;
  else
    return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}

//PulseMinSpeed - % for minimal speed
//PulseMaxSpeed - % for maximum speed
//PulseDuration - Duration (seconds) in which each pulse will be held. The pump will stay at minimal speed for PulseDuration and will stay at maximum speed for PulseDuration.
//PulseSync - true if you want to sync pumps to same cycle. one false and one true if you want to anti-sync pumps.
byte TunzeLongPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  byte tspeed=0;
  PulseMinSpeed=constrain(PulseMinSpeed,30,100);
  PulseMaxSpeed=constrain(PulseMaxSpeed,30,100);
  tspeed=(now()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
  if (PulseSync)
    return tspeed;
  else
    return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}


byte TunzeSineWave(boolean isleftpump, byte minspeed, byte maxspeed, int period_sec) {
  double x,y;

  x=double(now()%(period_sec));
  x/=period_sec;
  x*=2.0*PI;
  if (!isleftpump) x+=PI; // shift the sine wave for the right pump 

  y=sin(x);// y is now between -1 and 1
  y+=1.0; // y is now between 0 and 2
  y/=2.0; // y is now between 0 and 1 

  // now compute the tunze speed
  y*=double(maxspeed-minspeed);
  y+=double(minspeed); 

  y+=0.5; // for proper rounding

  // y is now between minspeed and maxspeed, constrain for safety 
  return constrain(byte(y),30,100); 
}


void RunTunzes() {

#ifdef TUNZE_MODE_SINE
  ReefAngel.PWM.SetDaylight(TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC)); // left tunze
  ReefAngel.PWM.SetActinic(TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC)); // right tunze
#endif

#ifdef TUNZE_MODE_LONG
  ReefAngel.PWM.SetDaylight(TunzeLongPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_LONGPULSE_SEC,true)); // left tunze
  ReefAngel.PWM.SetActinic(TunzeLongPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_LONGPULSE_SEC,TUNZE_LONGPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_SHORT
  ReefAngel.PWM.SetDaylight(TunzeShortPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_SHORTPULSE_MS,true)); // left tunze
  ReefAngel.PWM.SetActinic(TunzeShortPulse(TUNZE_MIN,TUNZE_MAX,TUNZE_SHORTPULSE_MS,TUNZE_SHORTPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_LONGSINE
  ReefAngel.PWM.SetDaylight(TunzeLongPulse(TUNZE_MIN,TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_LONGPULSE_SEC,true)); // left tunze
  ReefAngel.PWM.SetActinic(TunzeLongPulse(TUNZE_MIN,TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_LONGPULSE_SEC,TUNZE_LONGPULSE_SYNC)); // right tunze
#endif

#ifdef TUNZE_MODE_SHORTSINE
  ReefAngel.PWM.SetDaylight(TunzeShortPulse(TUNZE_MIN,TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_SHORTPULSE_MS,true)); // left tunze
  ReefAngel.PWM.SetActinic(TunzeShortPulse(TUNZE_MIN,TunzeSineWave(TUNZE_SINE_SYNC,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC),TUNZE_SHORTPULSE_MS,TUNZE_SHORTPULSE_SYNC)); // right tunze
#endif

}
Roberto.
carlii
Posts: 91
Joined: Sat Mar 17, 2012 7:22 pm

Re: Tunze Control

Post by carlii »

Thanks, it compiles now. So how do I assign this function to the Tunzes I have on my dimming expansion?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Tunze Control

Post by rimai »

You can add the channels to each function inside the RunTunzes() function
Like this:

Code: Select all

ReefAngel.PWM.SetChannel(0,TunzeSineWave(true,TUNZE_MIN,TUNZE_MAX,TUNZE_SINE_SEC));
Roberto.
carlii
Posts: 91
Joined: Sat Mar 17, 2012 7:22 pm

Re: Tunze Control

Post by carlii »

Works great! thanks.
Paulturner911
Posts: 288
Joined: Wed Jan 23, 2013 12:36 pm

Re: Tunze Control

Post by Paulturner911 »

#define TUNZE_MIN 30
#define TUNZE_MAX 75

Is this the strength of the flow in percentage?

Can you more than one mode at random to a channel?
Image
Post Reply