Controlling Jebao/Tunze/Speedwave pumps

Would you like to help?
Share your walkthrough tutorial with others

Posts: 12247
Joined: Fri Mar 18, 2011 6:47 pm
PostPosted: Sat Mar 30, 2013 10:00 pm
Hi Everyone,

With the libraries v1.0.4 release, all the wave pattern functions are already included. I'm still keeping the previous post at the bottom for reference, but please consider it deprecated and don't use it anymore.
If you followed the previous post prior to v1.0.4, you will need to remove all that code you added at the bottom of your code or you will get a lot of errors with the new update.
If this is your first time, all you need to do is choose which wave pattern you would like to use in the thread below and call it in your code.
viewtopic.php?f=7&t=2844

For this example, we will use ReefCrest wave pattern at speed 60% with +/- 20%, which will give you a range of 40% to 80%.
Inside your loop() section of your INO code, you will see a section like this:
Code: Select all
    ////// Place your custom code below here
   

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


You must place the wave pattern code between those two comment lines. It will end up being like this:
Code: Select all
    ////// Place your custom code below here
   
    ReefAngel.PWM.SetDaylight( ReefCrestMode(60,20,true) ); // ReefCrest at 60% +/- 20% on sync mode
    ReefAngel.PWM.SetActinic( ReefCrestMode(60,20,false) ); // ReefCrest at 60% +/- 20% on anti-sync mode

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

The above lines will place your daylight channel in sync mode and actinic channel in anti-sync mode.
Upload your code and watch your Jebao or Tunze pumps being controlled by your Reef Angel.
Enjoy :)

-------------------------------------------------------------------------------------------------------------------------

Original post just for reference. Do not use this anymore.
Hi Everyone,

With the Jebao cables coming out and several members already getting them and getting very confused on how to get the pumps to work with the cable, I decided to put this little tutorial. This tutorial can be used for both Jebao and Tunze pumps.
Because the code used in this tutorial are not yet released together with our libraries, this is a temporary tutorial.
So, this will be updated as the libraries get updated.
Let's get coding....
The first thing you want to do is copy and paste this code to the very end of your INO code. You will see that the last line of your code will be a }. Paste after the last bracket.
Code: Select all
byte ShortPulseMode(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;
}
byte LongPulseMode(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 SineMode(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync) {
  double x,y;

  x=double(now()%(PulseDuration));
  x/=PulseDuration;
  x*=2.0*PI;
  if (!PulseSync) 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(PulseMaxSpeed-PulseMinSpeed);
  y+=double(PulseMinSpeed);
 
  y+=0.5; // for proper rounding
 
  // y is now between PulseMinSpeed and PulseMaxSpeed, constrain for safety 
  return constrain(byte(y),30,100);
}
byte ReefCrestMode(byte WaveSpeed, byte WaveOffset, boolean PulseSync)
{
  static unsigned long lastwavemillis=millis();
  static int newspeed=WaveSpeed;
  if ((millis()-lastwavemillis) > 5000)
  {
    if (random(100)<50) newspeed--; else newspeed++;
    newspeed=constrain(newspeed,WaveSpeed-WaveOffset,WaveSpeed+WaveOffset);
    newspeed=constrain(newspeed,0,100);
    lastwavemillis=millis();
  } 
  if (PulseSync)
    return newspeed;
  else
    return WaveSpeed-(newspeed-WaveSpeed);
}
byte NutrientTransportMode(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  static unsigned long lastwavemillis=millis();
  static byte WavePhase=0;
  static time_t WaveStart=0;
  static byte speed=PulseMinSpeed;
  static byte anti_speed=PulseMinSpeed;

  if (WavePhase==0)
  {
    WavePhase++;
    WaveStart=now();
  }
  else if (WavePhase==1)
  {
    if (now()-WaveStart>2700)
    {
      WavePhase++;
    }
    if ((millis()-lastwavemillis) > PulseDuration)
    {
      if (speed==PulseMinSpeed)
      { 
        speed=PulseMaxSpeed;
        anti_speed=PulseMinSpeed;
      }
      else
      {
        speed=PulseMinSpeed;
        anti_speed=PulseMaxSpeed;
      }
      lastwavemillis=millis();
    }
  }
  else if (WavePhase==2)
  {
    if (now()-WaveStart>4500) WavePhase++;
    if (now()-WaveStart<=2760)
      speed=PulseMinSpeed;
    else
      speed=PulseMaxSpeed;
    if (now()-WaveStart<=3300)
      anti_speed=PulseMinSpeed;
    else
      anti_speed=PulseMaxSpeed*sin(radians(map(now()-WaveStart,3300,4500,0,180)));
  }
  else if (WavePhase==3)
  {
    if (now()-WaveStart>7200) WavePhase++;
    if ((millis()-lastwavemillis) > PulseDuration)
    {
      if (speed==PulseMinSpeed)
      { 
        speed=PulseMaxSpeed;
        anti_speed=PulseMinSpeed;
      }
      else
      {
        speed=PulseMinSpeed;
        anti_speed=PulseMaxSpeed;
      }
      lastwavemillis=millis();
    }
  }
  else if (WavePhase==4)
  {
    if (now()-WaveStart>9000) WavePhase=0;
    if (now()-WaveStart<=7260)
      speed=PulseMinSpeed;
    else
      speed=PulseMaxSpeed;
    if (now()-WaveStart<=8400)
      anti_speed=PulseMaxSpeed*sin(radians(map(now()-WaveStart,7200,8400,0,180)));
    else
      anti_speed=0;
  }
  if (PulseSync)
    return speed;
  else
    return anti_speed;
}
byte TidalSwellMode(byte WaveMaxSpeed, boolean PulseSync)
{
  static unsigned long lastwavemillis=millis();
  static byte WavePhase=0;
  static time_t WaveStart=0;
  static byte speed=0;
  static byte anti_speed=0;

  if (WavePhase==0)
  {
    WavePhase++;
    WaveStart=now();
  }
  else if (WavePhase==1)
  {
    if (now()-WaveStart>900) WavePhase++;
    speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,0,900,0,90))))/10;
    speed+=WaveMaxSpeed/2;

    anti_speed=(WaveMaxSpeed*2*sin(radians(map(now()-WaveStart,0,900,0,90))))/5;
    anti_speed+=WaveMaxSpeed/2;
  }
  else if (WavePhase==2)
  {
    if (now()-WaveStart>1800) WavePhase++;
    speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,900,1800,90,180))))/20;
    speed+=WaveMaxSpeed/2;
    speed+=WaveMaxSpeed/20;

    anti_speed=(WaveMaxSpeed*3*sin(radians(map(now()-WaveStart,900,1800,90,180))))/20;
    anti_speed+=WaveMaxSpeed/2;
    anti_speed+=WaveMaxSpeed/4;

  }
  else if (WavePhase==3)
  {
    if (now()-WaveStart>2700) WavePhase++;
    speed=(WaveMaxSpeed*3*sin(radians(map(now()-WaveStart,1800,2700,0,90))))/20;
    speed+=WaveMaxSpeed/2;
    speed+=WaveMaxSpeed/20;

    anti_speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,1800,2700,0,90))))/20;
    anti_speed+=WaveMaxSpeed/2;
    anti_speed+=WaveMaxSpeed/4;
  }
  else if (WavePhase==4)
  {
    if (now()-WaveStart>3600) WavePhase++;
    speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,2700,3600,90,180))))/20;
    speed+=WaveMaxSpeed/2;
    speed+=(WaveMaxSpeed*3)/20;

    anti_speed=(WaveMaxSpeed*3*sin(radians(map(now()-WaveStart,2700,3600,90,180))))/20;
    anti_speed+=WaveMaxSpeed/2;
    anti_speed+=(WaveMaxSpeed*3)/20;
  }
  else if (WavePhase==5)
  {
    if (now()-WaveStart>4500) WavePhase++;
    speed=(WaveMaxSpeed*3*sin(radians(map(now()-WaveStart,3600,4500,0,90))))/20;
    speed+=WaveMaxSpeed/2;
    speed+=(WaveMaxSpeed*3)/20;

    anti_speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,3600,4500,0,90))))/20;
    anti_speed+=WaveMaxSpeed/2;
    anti_speed+=(WaveMaxSpeed*3)/20;
  }
  else if (WavePhase==6)
  {
    if (now()-WaveStart>5400) WavePhase++;
    speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,4500,5400,90,180))))/20;
    speed+=WaveMaxSpeed/2;
    speed+=(WaveMaxSpeed*5)/20;

    anti_speed=(WaveMaxSpeed*3*sin(radians(map(now()-WaveStart,4500,5400,90,180))))/20;
    anti_speed+=WaveMaxSpeed/2;
    anti_speed+=WaveMaxSpeed/20;
  }
  else if (WavePhase==7)
  {
    if (now()-WaveStart>6300) WavePhase++;
    speed=(WaveMaxSpeed*3*sin(radians(map(now()-WaveStart,5400,6300,0,90))))/20;
    speed+=WaveMaxSpeed/2;
    speed+=(WaveMaxSpeed*5)/20;

    anti_speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,5400,6300,0,90))))/20;
    anti_speed+=WaveMaxSpeed/2;
    anti_speed+=WaveMaxSpeed/20;
  }
  else if (WavePhase==8)
  {
    if (now()-WaveStart>7200) WavePhase++;
    speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,6300,7200,90,180))))/20;
    speed+=WaveMaxSpeed/2;
    speed+=(WaveMaxSpeed*7)/20;

    anti_speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,6300,7200,90,180))))/10;
    anti_speed+=WaveMaxSpeed/2;
  }
  else if (WavePhase==9)
  {
    if (now()-WaveStart>8100) WavePhase++;
    speed=(WaveMaxSpeed*3*sin(radians(map(now()-WaveStart,7200,8100,0,90))))/20;
    speed+=WaveMaxSpeed/2;
    speed+=(WaveMaxSpeed*7)/20;

    anti_speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,7200,8100,0,90))))/2;
    anti_speed+=WaveMaxSpeed/2;
  }
  else if (WavePhase==10)
  {
    if (now()-WaveStart>9000) WavePhase=0;
    speed=(WaveMaxSpeed*sin(radians(map(now()-WaveStart,8100,9000,90,180))))/2;
    speed+=WaveMaxSpeed/2;

    anti_speed=speed;
  }

  if (PulseSync)
    return speed;
  else
    return anti_speed;
}
byte TideMode(byte WaveSpeed, byte minOffset, byte maxOffset)
{
  // Contribution of lnevo
  double moonOffset; // gap between high and low
  double amplitude;  // tide curve
  double wavelength=12*SECS_PER_HOUR;

  // Calculate the gap between high and low tide based on MoonPhase()
  moonOffset=cos(((2*PI)/100)*MoonPhase());
  moonOffset=((moonOffset+1)/2)*100; // Convert to percentage

  // Find out the current tidal height
  amplitude=sin(((2*PI)/wavelength)*now());

  moonOffset=map(moonOffset,0,100,minOffset,maxOffset);
  amplitude=amplitude*moonOffset;

  // Adjust the calculate speed to be in our adjusted range
  return constrain(WaveSpeed+amplitude,0,100);
}


Now, you must choose which wave pattern you wish to use. Please check this thread for the list of all wave patterns:
viewtopic.php?f=7&t=2844

For this example, we will use ReefCrest wave pattern at speed 60% with +/- 20%, which will give you a range of 40% to 80%.
Inside your loop() section of your INO code, you will see a section like this:
Code: Select all
    ////// Place your custom code below here
   

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


You must place the wave pattern code between those two comment lines. It will end up being like this:
Code: Select all
    ////// Place your custom code below here
   
    ReefAngel.PWM.SetDaylight( ReefCrestMode(60,20,true) ); // ReefCrest at 60% +/- 20% on sync mode
    ReefAngel.PWM.SetActinic( ReefCrestMode(60,20,false) ); // ReefCrest at 60% +/- 20% on anti-sync mode

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

The above lines will place your daylight channel in sync mode and actinic channel in anti-sync mode.
Upload your code and watch your Jebao or Tunze pumps being controlled by your Reef Angel.
Enjoy :)
Roberto.

Posts: 134
Joined: Tue Jan 24, 2012 6:20 pm
PostPosted: Sat Mar 30, 2013 10:12 pm
Awesome Roberto.

Posts: 411
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA
PostPosted: Sun Mar 31, 2013 4:54 am
thank you for this

Posts: 86
Joined: Sun Mar 03, 2013 8:37 am
PostPosted: Sat Apr 06, 2013 3:39 pm
Works great. Thanks fellas

Posts: 86
Joined: Sun Mar 03, 2013 8:37 am
PostPosted: Sun Apr 07, 2013 8:28 am
How would I select modes randomly?
Or maybe on a schedule?

Posts: 12247
Joined: Fri Mar 18, 2011 6:47 pm
PostPosted: Sun Apr 07, 2013 10:23 am
You could do something like this:
Code: Select all
if (hour()>=8 && hour()<12)
{
  ReefAngel.PWM.SetDaylight( ReefCrestMode(60,20,true) ); // ReefCrest at 60% +/- 20% on sync mode
  ReefAngel.PWM.SetActinic( ReefCrestMode(60,20,false) ); // ReefCrest at 60% +/- 20% on anti-sync mode
}
else if (hour()>=12 && hour()<18)
{
  ReefAngel.PWM.SetDaylight( ShortPulseMode(0,60,200,true) ); // Short pulse at 60% with 200ms pulse on sync mode
  ReefAngel.PWM.SetActinic( ShortPulseMode(0,60,200,false) ); // Short pulse at 60% with 200ms pulse on anti-sync mode
}
else
{
  ReefAngel.PWM.SetDaylight( LongPulseMode(0,60,10,true) ); // Long pulse at 60% with 10s pulse on sync mode
  ReefAngel.PWM.SetActinic( LongPulseMode(0,60,10,false) ); // Long pulse at 60% with 10s pulse on anti-sync mode
}
Roberto.

Posts: 86
Joined: Sun Mar 03, 2013 8:37 am
PostPosted: Sun Apr 07, 2013 2:23 pm
rimai wrote:You could do something like this:
Code: Select all
if (hour()>=8 && hour()<12)
{
  ReefAngel.PWM.SetDaylight( ReefCrestMode(60,20,true) ); // ReefCrest at 60% +/- 20% on sync mode
  ReefAngel.PWM.SetActinic( ReefCrestMode(60,20,false) ); // ReefCrest at 60% +/- 20% on anti-sync mode
}
else if (hour()>=12 && hour()<18)
{
  ReefAngel.PWM.SetDaylight( ShortPulseMode(0,60,200,true) ); // Short pulse at 60% with 200ms pulse on sync mode
  ReefAngel.PWM.SetActinic( ShortPulseMode(0,60,200,false) ); // Short pulse at 60% with 200ms pulse on anti-sync mode
}
else
{
  ReefAngel.PWM.SetDaylight( LongPulseMode(0,60,10,true) ); // Long pulse at 60% with 10s pulse on sync mode
  ReefAngel.PWM.SetActinic( LongPulseMode(0,60,10,false) ); // Long pulse at 60% with 10s pulse on anti-sync mode
}

Your the man Roberto

Posts: 411
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA
PostPosted: Sat Apr 13, 2013 6:40 am
Sorry for the n00b question.

I don't see the :
////// Place your custom code below here


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

Where can I find that ?
User avatar
Posts: 5349
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Sat Apr 13, 2013 6:48 am
It should be in the loop function after you use the wizard...

If not just make sure it is before the ShowInterface and Portal function.

Posts: 411
Joined: Sat Mar 30, 2013 5:02 pm
Location: CT, USA
PostPosted: Sat Apr 13, 2013 6:51 am
Thank you - I see it's not in the preloaded code but it was there when I used the Wizard.
Next

Return to Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest