The Planted Tank Forum banner

Guide: Arduino based LED controller for Current Satellite LED+

174K views 715 replies 69 participants last post by  Dahammer 
#1 · (Edited)
So I made an off-hand comment in one of Current USA's threads last night about an Arduino controller for their LED+ freshwater fixture. In the 12 or so hours since posting that, I have probably received a dozen PM's requesting code, IR protocol, sketches, or other information. Instead of responding to each request for information separately, it became obvious that I just needed to put together a thread for my project. This is that thread.

First, a disclaimer. While I'm not your average DIY tinkerer, I'm also not an electronics expert. I'm a mechanical engineer by day, and like to think of myself as a modern mad scientist by night. If you decide to build your own controller based on this thread, be aware that you're on your own. That's not to say I won't help... I think open source is the way of the future and love to pass knowledge on. I just mean that if you burn up your Arduino, yourself, or your house, that it's on you.

I'm putting together a guide to follow along, but none of the steps should be considered the last step. The nice thing about Arduino is how easy it is to constantly modify your code and add features. Throughout this thread, I will periodically post my newest code so that you can upload it and get the newer features. If you're experienced with Arduino, feel free to hack my code apart and have your way with it.

This process should work for any light fixture with some tweaking!

I'm writing this step-by-step so hopefully anyone can follow along. The more Arduino users we have in the world, the better life can be for everyone! If you're new to Arduino, don't be overwhelmed... it's not as difficult as it seems at first glance. And if you're an old hand please don't bash my primitive coding too much!



Everything in this post should be considered open source and public domain. Feel free to use my code, distribute it, hack it up, whatever.
 
See less See more
#48 ·
RTC just showed up!

This will allow the unit to keep it's own time without having to reset it any time the power goes out. I'll be back this afternoon hopefully with some details on how to hook it up and some updated code.

This is the TinyRTC V1.1... a DS1307 based real time clock.


 
#49 · (Edited)
Here is the 2.0 beta version of the new code including random thunderstorms. The code has been tested and compiles, but the randomness and frequency of the storms has yet to be seen.

This code is in testing and may cause strange operation until verified.

This code:

  • Randomly schedules a time for Storm2 mode.
  • Allows scheduled storm to proceed if chosen time is after 1 pm. Delays 24 hours and chooses new time if not.
  • Has random storm duration from 0-3 hours.
  • Has random after-storm gloom (Dawn/Dusk mode) from 0-1 hours.
  • Should return to previous mode after storm and gloom conclusion.
  • Should allow 1-2 storms per week to proceed.

Code:
///////////////////////////////////////////////////////////////////
// Current Satellite LED+ Controller  V2.0 Beta                  //
//   Indychus...Dahammer...mistergreen @ plantedtank.net         //
//   This code is public domain.  Pass it on.                    //
//   Confirmed on Arduino UNO 1.0.5                              //
//   Req. Time, TimeAlarms, DateTime, DateTimeStrings libraries  //
///////////////////////////////////////////////////////////////////

////////////SETUP//////////////////////////////////////////////////
#include <Time.h>
#include <TimeAlarms.h>
#include <DateTime.h>
#include <DateTimeStrings.h>

int IRledPin =  13;                  // Pin location for IR output

void setup()               
{ 
  pinMode(IRledPin, OUTPUT);         // Designate IRledPin as Output
  Serial.begin(9600);                // Connect @ (Baud)
  setTime(11,59,55,7,26,13);          // set time (HR,MIN,SEC,MO,DAY,YR)

  ////////////ALARM FUNCTIONS/////////////////////////////////////////
 
  ThunderStorm ();
 
  Alarm.alarmRepeat(7,00,0, DawnDusk);
  Alarm.alarmRepeat(7,00,0, DawnDusk);
  Alarm.alarmRepeat(9,00,0, Cloud2);     // (HR,MIN,SEC,FUNCTION)
  Alarm.alarmRepeat(9,00,0, Cloud2);
  Alarm.alarmRepeat(13,00,0, FullSpec);
  Alarm.alarmRepeat(13,00,0, FullSpec);
  Alarm.alarmRepeat(15,00,0, Cloud2);
  Alarm.alarmRepeat(15,00,0, Cloud2);
  Alarm.alarmRepeat(19,00,0, DawnDusk);
  Alarm.alarmRepeat(19,00,0, DawnDusk);
  Alarm.alarmRepeat(21,00,0, Night2);
  Alarm.alarmRepeat(21,00,0, Night2);
  Alarm.alarmRepeat(00,00,00, ThunderStorm); 
}   
////////////THUNDERSTORMS///////////////////////////////////////////// 
void ThunderStorm ()
{
  // Called everyday at midnight & randomly schedules a storm between 1 & 9 in the evening
  unsigned long RH = random(0,23);                   // Randomizer for thunderstorm
  unsigned long RM = random(0,59);
  unsigned long RS = random(0,59);
  unsigned long TSDuration = random(0,10800);     // Random T-Storm duration from 0-3hr

  Serial.print("Storm = ");
  Serial.print(RH);
  Serial.print(".");
  Serial.print(RM);
  Serial.print(".");
  Serial.print(RS);
  Serial.println();

  if (RH > 12)                             // If random value is after 1 pm, allow storm
  {
    Alarm.alarmOnce(RH,RM,RS,Storm2);
    if ((RH + (TSDuration/3600)) < 19) {
      // If storm is between 1 & 7
      Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,Cloud2);
    }
    else if ((RH + (TSDuration/3600)) < 21) {
      // If storm is between 1 & 9
      Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,DawnDusk);
    }
    else {
      Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,Night2);
    }
  }
}   


////////////CLOCK///////////////////////////////////////////////////
void  loop(){                       
  digitalClockDisplay();
  Alarm.delay(1000);               // Clock display update frequency (msec)
}

void digitalClockDisplay()          // Digital clock
{ 
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println(); 
}

void printDigits(int digits)        // Add :
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}


////////////SIGNAL///////////////////////////////////////////////////
// Create Frequency (38khz/26msec)
void pulseIR(long microsecs) 
{  
  cli();                           // kill interupts
  while (microsecs > 0)
  {  
    digitalWrite(IRledPin, HIGH);    // ~3 msec
    delayMicroseconds(7);            // ~delay
    digitalWrite(IRledPin, LOW);     // ~3 msec
    delayMicroseconds(7);            // ~delay
    microsecs -= 26;  
  }
  sei();  
}                           // zombie interupts


////////////FIXTURE FUNCTIONS////////////////////////////////////////
void DeviceID ()
{
  int codes[17][2] = { 
    {
      8840,4320    }
    , 
    {
      620,480    }
    , 
    {
      600,500    }
    , 
    {
      540,1660    }
    , 
    {
      580,520    }
    , 
    {
      520,560    }
    , 
    {
      600,480    }
    , 
    {
      620,480    }
    , 
    {
      540,540    }
    , 
    {
      620,1600    }
    , 
    {
      520,1660    }
    , 
    {
      580,520    }
    , 
    {
      520,1660    }
    , 
    {
      600,1580    }
    , 
    {
      620,1580    }
    , 
    {
      540,1660    }
    , 
    {
      600,1580    } 
  };

  for( int i = 0 ; i < 17; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
}

void Footer ()
{
  int codes[3][2] = { 
    {
      580,1620    }
    ,
    {
      540,38980    }
    ,
    {
      8860,2120    } 
  };

  for( int i = 0 ; i < 3; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
  pulseIR(620);
}

void IR(int codes[15][2]) 
{
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }  
  Footer(); 
}

void PowerButton()                             //Fixture power on/off toggle
{
  int codes[15][2] = { 
    {
      600,500    }
    ,
    {
      600,500    }
    ,
    {
      520,560    }
    ,
    {
      600,500    }
    ,
    {
      600,500    }
    ,
    {
      520,560    }
    ,
    {
      580,1620    }
    ,
    {
      540,540    }
    ,
    {
      600,1600    }
    ,
    {
      520,1660    }
    ,
    {
      580,1620    }
    ,
    {
      580,1620    }
    ,
    {
      520,1660    }
    ,
    {
      580,1600    }
    ,
    {
      580,520    } 
  }; 

  Serial.println("Power Toggle");
  IR(codes);
}

void Night2()                                   //Fixture Initialize Night2 Mode
{
  int codes[15][2] = { 
    {
      600,1640    }
    ,
    {
      600,500    }
    ,
    {
      520,560    }
    ,
    {
      600,1620    }
    ,
    {
      600,1640    }
    ,
    {
      520,560    }
    ,
    {
      580,540    }
    ,
    {
      540,540    }
    ,
    {
      600,480    }
    ,
    {
      520,1660    }
    ,
    {
      580,1620    }
    ,
    {
      580,500    }
    ,
    {
      520,500    }
    ,
    {
      580,1600    }
    ,
    {
      580,1560    } 
  }; 

  Serial.println("Night 2 Mode Initialized");
  IR(codes);
}

void Cloud2()                                         //Fixture Initialize Cloud2 Mode
{ 
  int codes[15][2] = { 
    {
      600,1580    }
    ,
    {
      600,500    }
    ,
    {
      520,1620    }
    ,
    {
      600,500    }
    ,
    {
      600,1600    }
    ,
    {
      520,560    }
    ,
    {
      580,480    }
    ,
    {
      540,540    }
    ,
    {
      600,560    }
    ,
    {
      520,1660    }
    ,
    {
      580,560    }
    ,
    {
      580,1620    }
    ,
    {
      520,560    }
    ,
    {
      580,1600    }
    ,
    {
      580,1640    } 
  };

  Serial.println("Cloud Cover 2 Mode Initialized");
  IR(codes);
}

void FullSpec()                                  //Fixture Initialize Full Spectrum Mode
{
  int codes[15][2] = { 
    {
      600,1580    }
    ,
    {
      600,500    }
    ,
    {
      520,480    }
    ,
    {
      600,1580    }
    ,
    {
      600,1600    }
    ,
    {
      520,560    }
    ,
    {
      580,1600    }
    ,
    {
      540,540    }
    ,
    {
      600,560    }
    ,
    {
      520,1660    }
    ,
    {
      580,1580    }
    ,
    {
      580,540    }
    ,
    {
      520,560    }
    ,
    {
      580,1600    }
    ,
    {
      580,480    } 
  };

  Serial.println("Full Spectrum Mode Initialized");
  IR(codes);
}

void DawnDusk()                         // Fixture Initialize Dawn/Dusk Mode
{
  int codes[15][2] = { 
    {
      600,1660    }
    ,
    {
      600,1560    }
    ,
    {
      520,480    }
    ,
    {
      600,1580    }
    ,
    {
      600,1600    }
    ,
    {
      520,560    }
    ,
    {
      580,500    }
    ,
    {
      540,540    }
    ,
    {
      600,560    }
    ,
    {
      520,500    }
    ,
    {
      580,1580    }
    ,
    {
      580,540    }
    ,
    {
      520,560    }
    ,
    {
      580,1660    }
    ,
    {
      580,1580    } 
  };

  Serial.println("Dawn/Dusk Mode Initialized");
  IR(codes);
}

void Storm2()                         //Fixture Initialize Storm2 Mode
{
  int codes[15][2] = { 
    {
      600,1660    }
    ,
    {
      600,540    }
    ,
    {
      520,480    }
    ,
    {
      600,500    }
    ,
    {
      600,1600    }
    ,
    {
      520,560    }
    ,
    {
      580,500    }
    ,
    {
      540,540    }
    ,
    {
      600,560    }
    ,
    {
      520,1660    }
    ,
    {
      580,1580    }
    ,
    {
      580,1620    }
    ,
    {
      520,560    }
    ,
    {
      580,1660    }
    ,
    {
      580,1580    } 
  };

  Serial.println("Storm2 Mode Initialized");
  IR(codes);
}
 
#50 ·
if the delayMicroseconds & pulseIR pair are always the same count, you can probably put them in an array and then loop through. It'll make things more tidy.


something like

Code:
int storm1_array[][] = { {1660,600}, {1560,520}, .... }

for( int i = 0 ; i < 15; i++) {
    delayMicroseconds(storm1_array[i][0]);
    pulseIR(storm1_array[i][1]);
}
 
#51 ·
Nice, thanks for the input. For each set, the first half of the values is the device ID and never changes, so that should work fine for those. I'll go back through and clean that up this weekend.

Sent from my HTC One X using Tapatalk 4 Beta
 
#52 ·
You could take it even further and just have a single function that you call to process the lighting changes, passing an array with the codes in it to the function when you call it. I think I'd also define all of the variables that users may want/need to modify in a library file. That way they'll be easy to find and you want have to go searching through all of the code looking for them.

I've order my fixture, now I just have to get an Arduino and some other parts.
 
#53 ·
I told you guys my programming was clunky haha. I'm pretty good at getting it to work, but making it elegant and user friendly takes me quite a while. I really need to get the RTC hooked up and working so I don't have to reset the time every time I upload a new sketch. Once that's done my main priority will be decoding the rest of the remote functions and cleaning the code up. I'd like to make a library with everything in it, but I don't have much experience making libraries and I keep getting some crazy errors.

V2.0 is running on my 55 right now, so far so good. It has scheduled a storm for around 5pm tomorrow. I have manually tested the storm's scheduling but tomorrow will be the first automated run.

Sent from my HTC One X
 
#55 ·
If you're interested in Dahammer's suggestion it would be something like this

Code:
int storm1_array[][] = { {1660,600}, {1560,520}, .... }
int dawn_array[][] = { {1600,400}, {1450,220}, .... }

void Storm1() {
    IR(storm1_array);
}

void Dawn() {
   IR(dawn_array);
}

void IR(int inArray[][]) {
    for( int i = 0 ; i < 15; i++) {
      delayMicroseconds(inArray[i][0]);
      pulseIR(inArray[i][1]);
    }
}
 
#56 ·
Thanks guys, I really appreciate the help. I will be out of town most of the weekend, but l will try to implement these suggestions early next week. I'm glad some of you have fixtures and/or Arduinos on the way to test this out on several lights.

Current has said that their IR protocol will be changing soon to help reduce interference with TVs, etc.... But it's easy to hack new protocols. I'm interested to see if different fixtures use the same device ID or not.

Sent from my HTC One X
 
#57 ·
The below code saves 2172 bytes. I haven't tested it, so be warned, but it does compile.

Code:
////////////FIXTURE FUNCTIONS////////////////////////////////////////
void DeviceID ()
{
  int codes[17][2] = { {8840,4320}, 
		       {620,480}, 
		       {600,500}, 
		       {540,1660}, 
		       {580,520}, 
		       {520,560}, 
		       {600,480}, 
		       {620,480}, 
		       {540,540}, 
		       {620,1600}, 
		       {520,1660}, 
		       {580,520}, 
		       {520,1660}, 
		       {600,1580}, 
		       {620,1580}, 
		       {540,1660}, 
		       {600,1580} };

  for( int i = 0 ; i < 17; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
}

void Footer ()
{
  int codes[3][2] = { {580,1620},
                      {540,38980},
                      {8860,2120} };
  	                            
  for( int i = 0 ; i < 3; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
    }
    pulseIR(620);
}

void PowerButton()                             //Fixture power on/off toggle
{
 int codes[15][2] = { {600,500},
                      {600,500},
                      {520,560},
                      {600,500},
                      {600,500},
                      {520,560},
                      {580,1620},
                      {540,540},
                      {600,1600},
                      {520,1660},
                      {580,1620},
                      {580,1620},
                      {520,1660},
                      {580,1600},
                      {580,520} }; 
  
  Serial.println("Power Toggle");
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }  
  Footer(); 
}
 
void Night2()                                   //Fixture Initialize Night2 Mode
{
  int codes[15][2] = { {600,1640},
                       {600,500},
                       {520,560},
                       {600,1620},
                       {600,1640},
                       {520,560},
                       {580,540},
                       {540,540},
                       {600,480},
                       {520,1660},
                       {580,1620},
                       {580,500},
                       {520,500},
                       {580,1600},
                       {580,1560} }; 
   
  Serial.println("Night 2 Mode Initialized");
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
  Footer();
}
     
void Cloud2()                                         //Fixture Initialize Cloud2 Mode
{ 
   int codes[15][2] = { {600,1580},
                        {600,500},
                        {520,1620},
                        {600,500},
                        {600,1600},
                        {520,560},
                        {580,480},
                        {540,540},
                        {600,560},
                        {520,1660},
                        {580,560},
                        {580,1620},
                        {520,560},
                        {580,1600},
                        {580,1640} };
                        
  Serial.println("Cloud Cover 2 Mode Initialized");
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
  Footer();
}
   
void FullSpec()                                  //Fixture Initialize Full Spectrum Mode
{
  int codes[15][2] = { {600,1580},
                       {600,500},
                       {520,480},
                       {600,1580},
                       {600,1600},
                       {520,560},
                       {580,1600},
                       {540,540},
                       {600,560},
                       {520,1660},
                       {580,1580},
                       {580,540},
                       {520,560},
                       {580,1600},
                       {580,480} };
  
  Serial.println("Full Spectrum Mode Initialized");
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
  Footer();
}
    
void DawnDusk()                         // Fixture Initialize Dawn/Dusk Mode
{
  int codes[15][2] = { {600,1660},
                       {600,1560},
                       {520,480},
                       {600,1580},
                       {600,1600},
                       {520,560},
                       {580,500},
                       {540,540},
                       {600,560},
                       {520,500},
                       {580,1580},
                       {580,540},
                       {520,560},
                       {580,1660},
                       {580,1580} };
    
  Serial.println("Dawn/Dusk Mode Initialized");
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
  Footer();
}

void Storm2()                         //Fixture Initialize Storm2 Mode
{
  int codes[15][2] = { {600,1660},
                       {600,540},
                       {520,480},
                       {600,500},
                       {600,1600},
                       {520,560},
                       {580,500},
                       {540,540},
                       {600,560},
                       {520,1660},
                       {580,1580},
                       {580,1620},
                       {520,560},
                       {580,1660},
                       {580,1580} };
    
  Serial.println("Storm2 Mode Initialized");
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
  Footer();
}
 
#58 ·
Using mistergreen's suggestion saves another 272 bytes. You probably won't ever use all of the Uno's memory, but you can't ever tell. I left the code arrays local instead of making them global. If you wanted to make them global you could do that though, but I don't see any benefit other than it would allow you to keep all of them in one spot like at the top of the source. Wish I had an Arduino to play with. Might have to make trip to Radio Shack!

Code:
////////////FIXTURE FUNCTIONS////////////////////////////////////////
void DeviceID ()
{
  int codes[17][2] = { {8840,4320}, 
		       {620,480}, 
		       {600,500}, 
		       {540,1660}, 
		       {580,520}, 
		       {520,560}, 
		       {600,480}, 
		       {620,480}, 
		       {540,540}, 
		       {620,1600}, 
		       {520,1660}, 
		       {580,520}, 
		       {520,1660}, 
		       {600,1580}, 
		       {620,1580}, 
		       {540,1660}, 
		       {600,1580} };

  for( int i = 0 ; i < 17; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }
}

void Footer ()
{
  int codes[3][2] = { {580,1620},
                      {540,38980},
                      {8860,2120} };
  	                            
  for( int i = 0 ; i < 3; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
    }
    pulseIR(620);
}

void IR(int codes[15][2]) 
{
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }  
  Footer(); 
}

void PowerButton()                             //Fixture power on/off toggle
{
 int codes[15][2] = { {600,500},
                      {600,500},
                      {520,560},
                      {600,500},
                      {600,500},
                      {520,560},
                      {580,1620},
                      {540,540},
                      {600,1600},
                      {520,1660},
                      {580,1620},
                      {580,1620},
                      {520,1660},
                      {580,1600},
                      {580,520} }; 
  
  Serial.println("Power Toggle");
  IR(codes);
}
 
void Night2()                                   //Fixture Initialize Night2 Mode
{
  int codes[15][2] = { {600,1640},
                       {600,500},
                       {520,560},
                       {600,1620},
                       {600,1640},
                       {520,560},
                       {580,540},
                       {540,540},
                       {600,480},
                       {520,1660},
                       {580,1620},
                       {580,500},
                       {520,500},
                       {580,1600},
                       {580,1560} }; 
   
  Serial.println("Night 2 Mode Initialized");
  IR(codes);
}
     
void Cloud2()                                         //Fixture Initialize Cloud2 Mode
{ 
   int codes[15][2] = { {600,1580},
                        {600,500},
                        {520,1620},
                        {600,500},
                        {600,1600},
                        {520,560},
                        {580,480},
                        {540,540},
                        {600,560},
                        {520,1660},
                        {580,560},
                        {580,1620},
                        {520,560},
                        {580,1600},
                        {580,1640} };
                        
  Serial.println("Cloud Cover 2 Mode Initialized");
  IR(codes);
}
   
void FullSpec()                                  //Fixture Initialize Full Spectrum Mode
{
  int codes[15][2] = { {600,1580},
                       {600,500},
                       {520,480},
                       {600,1580},
                       {600,1600},
                       {520,560},
                       {580,1600},
                       {540,540},
                       {600,560},
                       {520,1660},
                       {580,1580},
                       {580,540},
                       {520,560},
                       {580,1600},
                       {580,480} };
  
  Serial.println("Full Spectrum Mode Initialized");
  IR(codes);
}
    
void DawnDusk()                         // Fixture Initialize Dawn/Dusk Mode
{
  int codes[15][2] = { {600,1660},
                       {600,1560},
                       {520,480},
                       {600,1580},
                       {600,1600},
                       {520,560},
                       {580,500},
                       {540,540},
                       {600,560},
                       {520,500},
                       {580,1580},
                       {580,540},
                       {520,560},
                       {580,1660},
                       {580,1580} };
    
  Serial.println("Dawn/Dusk Mode Initialized");
  IR(codes);
}

void Storm2()                         //Fixture Initialize Storm2 Mode
{
  int codes[15][2] = { {600,1660},
                       {600,540},
                       {520,480},
                       {600,500},
                       {600,1600},
                       {520,560},
                       {580,500},
                       {540,540},
                       {600,560},
                       {520,1660},
                       {580,1580},
                       {580,1620},
                       {520,560},
                       {580,1660},
                       {580,1580} };
    
  Serial.println("Storm2 Mode Initialized");
  IR(codes);
}
 
#60 · (Edited)
True. He was having issues moving code to a library earlier, not sure if he worked that out or not.

I've been working on it in preparation of getting mine going, but I don't have any way of testing it yet, so I'm hesitant to post it. But here is what I have so far if anyone else wants to play with it. Just be WARNED, it may not work. I moved the code arrays to a library file (LED_Controller.h)(wasn't sure what IndyChus was going to name this project) and added code to make use of an RTC. The RTC code requires a library from Adafruit and there is a link at the top of the source. It compiles fine for me, but that's all I've done with it.

Again, I've got several years of rust on my C/C++ hacking, so I'm likely to have made an error somewhere.

Code:
///////////////////////////////////////////////////////////////////
// Current Satellite LED+ Controller                             //
//   Ken Bunton (Indychus)                                       //
//   This code is public domain.  Pass it on.                    //
//   Confirmed on Arduino UNO 1.0.5                              //
//   Req. Time, TimeAlarms, DateTime, DateTimeStrings libraries  //
///////////////////////////////////////////////////////////////////

/*
BETA!! NOT TESTED!!!!!!
Requires RTClib & an RTC board for the Arduino to get RTC function
https://github.com/adafruit/RTClib/archive/master.zip
*/

////////////SETUP//////////////////////////////////////////////////
#include <Wire.h>
#include "RTClib.h"
#include "Time.h"
#include "TimeAlarms.h"
#include "LED_Controller.h"


RTC_DS1307 RTC;

int IRledPin =  13;                  // Pin location for IR output

void setup()               
{ 
  pinMode(IRledPin, OUTPUT);         // Designate IRledPin as Output
  Serial.begin(9600);                // Connect @ (Baud)    
  Wire.begin();
  RTC.begin();
  
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  setSyncProvider(syncProvider);     //reference our syncProvider function instead of RTC_DS1307::get()

////////////ALARM FUNCTIONS/////////////////////////////////////////
  Alarm.alarmRepeat(7,00,0, DawnDusk);
  Alarm.alarmRepeat(7,00,1, DawnDusk);
  Alarm.alarmRepeat(9,00,0, Cloud2);     // (HR,MIN,SEC,FUNCTION)
  Alarm.alarmRepeat(9,00,1, Cloud2);
  Alarm.alarmRepeat(13,00,0, FullSpec);
  Alarm.alarmRepeat(13,00,1, FullSpec);
  Alarm.alarmRepeat(15,00,0, Cloud2);
  Alarm.alarmRepeat(15,00,1, Cloud2);
  Alarm.alarmRepeat(19,00,0, DawnDusk);
  Alarm.alarmRepeat(19,00,1, DawnDusk);
  Alarm.alarmRepeat(21,00,0, Night2);
  Alarm.alarmRepeat(21,00,1, Night2);    
  
  
 ////////////THUNDERSTORMS///////////////////////////////////////////// 
  unsigned long RH = random(0,23);                   // Randomizer for thunderstorm
  unsigned long RM = random(0,59);
  unsigned long RS = random(0,59);
  unsigned long TSDuration = random(0,10800000);     // Random T-Storm duration from 0-3hr
  unsigned long RecoveryDelay = random(0,3600000);   // Random after storm gloominess from 0-1hr
  
  Serial.print("RH = ");
  Serial.print(RH);
  Serial.println();
  
    
  if (RH > 12)                             // If random value is after 1 pm, allow storm
  {Alarm.alarmOnce(RH,RM,RS,Storm2);
  
  if (12 < (RH + (TSDuration/3600000)) < 19) 
  {Alarm.alarmOnce((RH + (TSDuration/3600000) + (RecoveryDelay/3600000)),Cloud2);}
  
  if (12 <= (RH + (TSDuration/3600000)) < 21)
  {Alarm.alarmOnce((RH + (TSDuration/3600000)),DawnDusk);}
  
  if ((RH + (TSDuration/3600000)) >= 21)
  {Alarm.alarmOnce((RH + (TSDuration/3600000)),Night2);}
  
  
      RH = random(0,23);                                  // Reset random values after storm
      RM = random(0,59);
      RS = random(0,59);
      TSDuration = random(0,10800000);
      RecoveryDelay = random(0,3600000);}
      
   
if (RH <= 12)                                           // Delay when storm = FALSE
{Alarm.alarmOnce(0,0,0,reset);}}
  
void reset(){
  unsigned long RH = random(0,23);                   // Randomizer for thunderstorm
  unsigned long RM = random(0,59);
  unsigned long RS = random(0,59);
  unsigned long TSDuration = random(0,10800000);     // Random T-Storm duration from 0-3hr
  unsigned long RecoveryDelay = random(0,3600000);}   // Random after storm gloominess from 0-1hr} 


////////////CLOCK///////////////////////////////////////////////////
void  loop(){                       
  digitalClockDisplay();
  Alarm.delay(3600000/4); }              // Clock display update frequency (msec)

time_t syncProvider()     //this does the same thing as RTC_DS1307::get()
{
  return RTC.now().unixtime();
}

void digitalClockDisplay()          // Digital clock
{ Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println(); }

void printDigits(int digits)        // Add :
{Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);}

  
////////////SIGNAL///////////////////////////////////////////////////
// Create Frequency (38khz/26msec)
void pulseIR(long microsecs) 
{  cli();                           // kill interupts
  while (microsecs > 0)
{  digitalWrite(IRledPin, HIGH);    // ~3 msec
   delayMicroseconds(7);            // ~delay
   digitalWrite(IRledPin, LOW);     // ~3 msec
   delayMicroseconds(7);            // ~delay
    microsecs -= 26;  }
sei();  }                           // zombie interupts


////////////FIXTURE FUNCTIONS////////////////////////////////////////
void DeviceID ()
{
  for( int i = 0 ; i < 17; i++) {
    pulseIR(DeviceID_codes[i][0]);
    delayMicroseconds(DeviceID_codes[i][1]);
  }
}

void Footer ()
{
 for( int i = 0 ; i < 3; i++) {
    pulseIR(Footer_codes[i][0]);
    delayMicroseconds(Footer_codes[i][1]);
    }
    pulseIR(620);
}

void IR(int codes[15][2]) 
{
  DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);
  }  
  Footer(); 
}

void PowerButton()                             //Fixture power on/off toggle
{
  Serial.println("Power Toggle");
  IR(PowerButton_codes);
}
 
void Night2()                                   //Fixture Initialize Night2 Mode
{
  Serial.println("Night 2 Mode Initialized");
  IR(Night2_codes);
}
     
void Cloud2()                                         //Fixture Initialize Cloud2 Mode
{
  Serial.println("Cloud Cover 2 Mode Initialized");
  IR(Cloud2_codes);
}
   
void FullSpec()                                  //Fixture Initialize Full Spectrum Mode
{
  Serial.println("Full Spectrum Mode Initialized");
  IR(FullSpec_codes);
}
    
void DawnDusk()                         // Fixture Initialize Dawn/Dusk Mode
{
  Serial.println("Dawn/Dusk Mode Initialized");
  IR(DawnDusk_codes);
}

void Storm2()                         //Fixture Initialize Storm2 Mode
{
  Serial.println("Storm2 Mode Initialized");
  IR(Storm2_codes);
}
Here is the library file:
Code:
//   LED_Controller.h

int DeviceID_codes[17][2] = { {8840,4320},{620,480},{600,500},{540,1660},{580,520}, 
                              {520,560},{600,480},{620,480},{540,540},{620,1600}, 
                              {520,1660},{580,520},{520,1660},{600,1580},{620,1580}, 
                              {540,1660},{600,1580} };

int Footer_codes[3][2] = { {580,1620},{540,38980},{8860,2120} };
                           
int PowerButton_codes[15][2] = { {600,500},{600,500},{520,560},{600,500},{600,500},
                                 {520,560},{580,1620},{540,540},{600,1600},{520,1660},
                                 {580,1620},{580,1620},{520,1660},{580,1600},{580,520} };
                                  
int Night2_codes[15][2] = { {600,1640},{600,500},{520,560},{600,1620},{600,1640},
                            {520,560},{580,540},{540,540},{600,480},{520,1660},
                            {580,1620},{580,500},{520,500},{580,1600},{580,1560} };
                                  
int Cloud2_codes[15][2] = { {600,1580},{600,500},{520,1620},{600,500},{600,1600},
                            {520,560},{580,480},{540,540},{600,560},{520,1660},
                            {580,560},{580,1620},{520,560},{580,1600},{580,1640} };  

int FullSpec_codes[15][2] = { {600,1580},{600,500},{520,480},{600,1580},{600,1600},
                              {520,560},{580,1600},{540,540},{600,560},{520,1660},
                              {580,1580},{580,540},{520,560},{580,1600},{580,480} };
                              
int DawnDusk_codes[15][2] = { {600,1660},{600,1560},{520,480},{600,1580},{600,1600},
                              {520,560},{580,500},{540,540},{600,560},{520,500},
                              {580,1580},{580,540},{520,560},{580,1660},{580,1580} };
                              
int Storm2_codes[15][2] = { {600,1660},{600,540},{520,480},{600,500},{600,1600},
                            {520,560},{580,500},{540,540},{600,560},{520,1660},
                            {580,1580},{580,1620},{520,560},{580,1660},{580,1580} };
Also, I don't see how the thunderstorm code can work as is if the random hour is <= 12. That last alarm calls reset() and it looks like reset() attempts to change variables that are local to setup(). And setup() doesn't execute any time other than at startup (as I understand the Arduino), so you'd probably need the thunderstorm code in it's on function, so you could call it with the event to re-randomize them.
 
#63 ·
Wow! You guys are a tremendous help. I will be able to merge your code into mine and test it tomorrow when I get home.

In the meantime, here's some output that my PC at home just emailed me:

RH = 17
RH = 8
11:59:00
12:14:00
12:29:00
12:44:00
12:59:00
Full Spectrum Mode Initialized
Full Spectrum Mode Initialized
13:14:00
13:29:00
13:44:00
13:59:00
14:14:00
14:29:00
14:44:00
14:59:00
Cloud Cover 2 Mode Initialized
Cloud Cover 2 Mode Initialized
15:14:00
15:29:00
15:44:00
15:59:00
16:14:00
16:29:00
16:44:00
16:59:00
Storm2 Mode Initialized
17:14:00
17:29:00
17:44:00
17:59:00
Cloud Cover 2 Mode Initialized
Dawn/Dusk Mode Initialized
18:14:00
18:29:00
18:44:00
18:59:00
Dawn/Dusk Mode Initialized
Dawn/Dusk Mode Initialized
19:14:00
19:29:00
19:44:00
19:59:00
20:14:00
20:29:00
20:44:00
20:59:00
Night 2 Mode Initialized
Night 2 Mode Initialized
21:14:00
21:29:00
21:44:00
21:59:00
...
...
5:59:00
6:14:00
6:29:00
6:44:00
6:59:00
Dawn/Dusk Mode Initialized
Dawn/Dusk Mode Initialized
7:14:00
7:29:00
7:44:00
7:59:00
8:14:00
8:29:00
8:44:00
8:59:00
Cloud Cover 2 Mode Initialized
Cloud Cover 2 Mode Initialized
9:14:00
9:29:00
9:44:00
9:59:00
...
...
12:14:00
12:29:00
12:44:00

You can see that it triggered a successful storm yesterday a little after 5 pm, then recovered and continued into normal operation again. It did fire the cloud2 and dawn/dusk modes after the storm backwards for some reason; I'll troubleshoot that tonight.
 
#65 ·
Yeah, I think there are issues with the thunderstorm code. The reason it fired backwards is probably here:
Code:
  if (12 < (RH + (TSDuration/3600000)) < 19) 
  {Alarm.alarmOnce((RH + (TSDuration/3600000) + (RecoveryDelay/3600000)),Cloud2);}
  
  if (12 <= (RH + (TSDuration/3600000)) < 21)
  {Alarm.alarmOnce((RH + (TSDuration/3600000)),DawnDusk);}
First, I don't think this works as you are intending. RH has to be greater than 12 to reach the above code. Both of the expressions are always TRUE. First it compares 12 to ((RH + (TSDuration/3600000)), which is going to be true otherwise we wouldn't be executing this code. TRUE becomes a 1 and then 1 is less than 19 & 21, so that's also true, so it sets both alarms.

The reason they went in reverse is because RecoveryDelay is added to alarm on the for the clouds. I'm not sure I understand exactly are you wanting to do here.

Could also use a toggle switch to turn on/off features like the thunderstorm feature. That would be neat.
 
#66 ·
I'm trying to get it to always do dawn/dusk for a random time after the storm, then return to the previous mode... cloud2 before 19.00 and night2 after 21.00. from 19.00 to 21.00 it would just stay in dawn/dusk.

**Edited code in above post
 
#67 ·
Ok, edited it once again... it seems to be working right (it compiles and schedules a random storm)... since it's only psuedo-random I get an RH of 17 again to start with. Still not sure about scheduling the dawndusk and cloud2 when (RH + TSDuration) is between 19 and 21. If I manually set RH to any value outside of this range it seems to work as intended. See what you think.
 
#69 ·
I think I see what you are trying to do. You want the storms to last for 0-3 hours and always be followed up by clouds if the time is between 13 & 19. If it's between 19 & 21, you want the storm followed by dawndusk. If it's after 21, you want it followed by night. This correct?
 
#68 ·
Setting the storm time variables to global variables isn't really doing anything. alarmOnce uses the values you call it with to schedule an alarm. Changing those values after the call isn't going to have any effect on the scheduled alarm.

As is, you should only get 1 storm (if that) and then never see it again. This is because the setup() code is only ran once, only at startup, so your call to it in setup() never happens again after the Ardunio starts up. You could just add an alarmRepeat call to storm() in setup so it's called every day. Then you'd get a chance for a storm every day. If you don't want a chance of storm every day, then you can use dowDayofweek in your call to alarmRepeat to only do it on certain days, like dowSaturday for Saturdays and etc.
 
#71 ·
When you need things to happen in sequence it's good to use a 'finite state machine' coding method. It's basically, 'switches' to turn things on & off.

You can use 'if/then' conditions but easier to see/read with 'switch/case'.

It'll look something like this

Code:
void loop()
{
  static int state = 1; // initial state is 1, the "idle" state.
  static unsigned long ts;  // To store the "current" time in for delays.

  switch(state)
  {
    case 1:
      // We don't need to do anything here, waiting for a forced state change.
      break;
    case 2:
      // turn on storm
      ts = millis();  // Remember the current time
      state = 3;  // Move to the next state
      break;
    case 3:
      // If 19 seconds has passed, then move on to the next state.
      if(millis() > ts + 19000)
      {
        state = 4;
      }
      break;
    case 4:
       //turn on dawn - randomly or not. You can use a random function
      // like 
      // if(random(4) == 1) callDawnFunction
       break;
    default:
      state = 1;
      break;
   }
}
 
#72 · (Edited)
Try this, less the RTC code. I also eliminated the reset function and globals to store the times in.

Code:
void setup()               
{ 
  pinMode(IRledPin, OUTPUT);         // Designate IRledPin as Output
  Serial.begin(9600);                // Connect @ (Baud)    
  Wire.begin();
  RTC.begin();
  
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  setSyncProvider(syncProvider);     //reference our syncProvider function instead of RTC_DS1307::get()

////////////ALARM FUNCTIONS/////////////////////////////////////////
  Alarm.alarmRepeat(7,00,0, DawnDusk);
  Alarm.alarmRepeat(7,00,1, DawnDusk);
  Alarm.alarmRepeat(9,00,0, Cloud2);     // (HR,MIN,SEC,FUNCTION)
  Alarm.alarmRepeat(9,00,1, Cloud2);
  Alarm.alarmRepeat(11,00,0, FullSpec);
  Alarm.alarmRepeat(11,00,1, FullSpec);
  Alarm.alarmRepeat(15,00,0, Cloud2);
  Alarm.alarmRepeat(15,00,1, Cloud2);
  Alarm.alarmRepeat(19,00,0, DawnDusk);
  Alarm.alarmRepeat(19,00,1, DawnDusk);
  Alarm.alarmRepeat(21,00,0, Night2);
  Alarm.alarmRepeat(21,00,1, Night2);
  Alarm.alarmRepeat(0,0,0, ThunderStorm);

  ThunderStorm(); // Schedule the first storm
  
}

void ThunderStorm ()
{
  // Called everyday at midnight & randomly schedules a storm between 1 & 9 in the evening
  unsigned long RH = random(0,23);                   // Randomizer for thunderstorm
  unsigned long RM = random(0,59);
  unsigned long RS = random(0,59);
  unsigned long TSDuration = random(0,10800);     // Random T-Storm duration from 0-3hr
  unsigned long RecoveryDelay = random(0,3600);   // Random after storm gloominess from 0-1hr
  
  Serial.print("RH = ");
  Serial.print(RH);
  Serial.println();
      
  if (RH > 12)                             // If random value is after 1 pm, allow storm
    {
      Alarm.alarmOnce(RH,RM,RS,Storm2);
      if ((RH + (TSDuration/3600)) < 19) {
        // If storm is between 1 & 7, follow with clouds
        Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,Cloud2);
      }
      else if ((RH + (TSDuration/3600)) < 21) {
        // If storm is between 7 & 9, follow with dawndusk
        Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,DawnDusk);
        }
      else {
        Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,Night2);
      }
    }
}
 
#73 ·
Try this, less the RTC code.

Code:
void setup()               
{ 
  pinMode(IRledPin, OUTPUT);         // Designate IRledPin as Output
  Serial.begin(9600);                // Connect @ (Baud)    
  Wire.begin();
  RTC.begin();
  
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  setSyncProvider(syncProvider);     //reference our syncProvider function instead of RTC_DS1307::get()

////////////ALARM FUNCTIONS/////////////////////////////////////////
  Alarm.alarmRepeat(7,00,0, DawnDusk);
  Alarm.alarmRepeat(7,00,1, DawnDusk);
  Alarm.alarmRepeat(9,00,0, Cloud2);     // (HR,MIN,SEC,FUNCTION)
  Alarm.alarmRepeat(9,00,1, Cloud2);
  Alarm.alarmRepeat(11,00,0, FullSpec);
  Alarm.alarmRepeat(11,00,1, FullSpec);
  Alarm.alarmRepeat(15,00,0, Cloud2);
  Alarm.alarmRepeat(15,00,1, Cloud2);
  Alarm.alarmRepeat(19,00,0, DawnDusk);
  Alarm.alarmRepeat(19,00,1, DawnDusk);
  Alarm.alarmRepeat(21,00,0, Night2);
  Alarm.alarmRepeat(21,00,1, Night2);
  Alarm.alarmRepeat(0,0,0, ThunderStorm);
  
}

void ThunderStorm ()
{
  // Called everyday at midnight & randomly schedules a storm between 1 & 9 in the evening
  unsigned long RH = random(0,23);                   // Randomizer for thunderstorm
  unsigned long RM = random(0,59);
  unsigned long RS = random(0,59);
  unsigned long TSDuration = random(0,10800);     // Random T-Storm duration from 0-3hr
  unsigned long RecoveryDelay = random(0,3600);   // Random after storm gloominess from 0-1hr
  
  Serial.print("RH = ");
  Serial.print(RH);
  Serial.println();
      
  if (RH > 12)                             // If random value is after 1 pm, allow storm
    {
      Alarm.alarmOnce(RH,RM,RS,Storm2);
      if ((RH + (TSDuration/3600)) < 19) {
        // If storm is between 1 & 7
        Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,Cloud2);
      }
      else if ((RH + (TSDuration/3600)) < 21) {
        // If storm is between 1 & 9
        Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,DawnDusk);
        }
      else {
        Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,Night2);
      }
    }
}
Ok, yeah... that looks like it's doing the same thing I was trying to do, just much simpler. I was trying to do an approach like mistergreen posted above based on cases and using the millis(), but couldn't get it to compile... I got so deep into it that by the time I went back to if/then I couldn't see the forest for the trees haha.

Just uploaded it to the Uno, we'll see how it does...
 
#75 · (Edited)
Ok, here we go... This is definitely working, but I want to let it run for a few days before calling it good. Also, I'm gonna go back through the thread and delete some of my failed attempts to clean it up in case anyone else is trying to make sense of my mess haha.

Code:
///////////////////////////////////////////////////////////////////
// Current Satellite LED+ Controller  V2.0 Beta                  //
//   Indychus...Dahammer...mistergreen @ plantedtank.net         //
//   This code is public domain.  Pass it on.                    //
//   Confirmed on Arduino UNO 1.0.5                              //
//   Req. Time, TimeAlarms, DateTime, DateTimeStrings libraries  //
///////////////////////////////////////////////////////////////////

////////////SETUP//////////////////////////////////////////////////
#include <Time.h>
#include <TimeAlarms.h>
#include <DateTime.h>
#include <DateTimeStrings.h>

int IRledPin =  13;                  // Pin location for IR output

void setup()               
{ pinMode(IRledPin, OUTPUT);         // Designate IRledPin as Output
  Serial.begin(9600);                // Connect @ (Baud)
  setTime(18,24,15,7,26,13);          // set time (HR,MIN,SEC,MO,DAY,YR)

  ////////////ALARM FUNCTIONS/////////////////////////////////////////
 
  ThunderStorm ();
 
  Alarm.alarmRepeat(7,00,0, DawnDusk);
  Alarm.alarmRepeat(7,00,0, DawnDusk);
  Alarm.alarmRepeat(9,00,0, Cloud2);     // (HR,MIN,SEC,FUNCTION)
  Alarm.alarmRepeat(9,00,0, Cloud2);
  Alarm.alarmRepeat(13,00,0, FullSpec);
  Alarm.alarmRepeat(13,00,0, FullSpec);
  Alarm.alarmRepeat(15,00,0, Cloud2);
  Alarm.alarmRepeat(15,00,0, Cloud2);
  Alarm.alarmRepeat(19,00,0, DawnDusk);
  Alarm.alarmRepeat(19,00,0, DawnDusk);
  Alarm.alarmRepeat(21,00,0, Night2);
  Alarm.alarmRepeat(21,00,0, Night2);
  Alarm.alarmRepeat(00,00,00, ThunderStorm); 
}   
////////////THUNDERSTORMS///////////////////////////////////////////// 
void ThunderStorm ()
{ // Called everyday at midnight & randomly schedules a storm between 1 & 9 in the evening
  unsigned long RH = random(0,23);                   // Randomizer for thunderstorm
  unsigned long RM = random(0,59);
  unsigned long RS = random(0,59);
  unsigned long TSDuration = random(0,10800);     // Random T-Storm duration from 0-3hr

  Serial.print("Storm = ");
  Serial.print(RH);
  Serial.print(".");
  Serial.print(RM);
  Serial.print(".");
  Serial.print(RS);
  Serial.println();

  if (RH > 12)                             // If random value is after 1 pm, allow storm
      {Alarm.alarmOnce(RH,RM,RS,Storm2);
      
      if ((RH + (TSDuration/3600)) < 19)   // Return to Cloud2 if storm ends between 1-7pm
        {Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,Cloud2);}
      
      else if ((RH + (TSDuration/3600)) < 21)  // Return to DawnDusk if storm ends between 7-9pm
        {Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,DawnDusk);}
      
      else                                       // Return to Night2 if storm ends after 9pm
        {Alarm.alarmOnce((RH + (TSDuration/3600)),RM,RS,Night2);}}}   


////////////CLOCK///////////////////////////////////////////////////
void  loop(){                       
  digitalClockDisplay();
  Alarm.delay(1000);               // Clock display update frequency (msec)
}

void digitalClockDisplay()          // Digital clock
{ 
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println(); 
}

void printDigits(int digits)        // Add :
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}


////////////SIGNAL///////////////////////////////////////////////////
// Create Frequency (38khz/26msec)
void pulseIR(long microsecs) 
{  
  cli();                           // kill interupts
  while (microsecs > 0)
  {  
    digitalWrite(IRledPin, HIGH);    // ~3 msec
    delayMicroseconds(7);            // ~delay
    digitalWrite(IRledPin, LOW);     // ~3 msec
    delayMicroseconds(7);            // ~delay
    microsecs -= 26;  
  }
  sei();  
}                           // zombie interupts


////////////FIXTURE FUNCTIONS////////////////////////////////////////
void DeviceID ()
{
  int codes[17][2] = { 
    {8840,4320}, 
    {620,480}, 
    {600,500}, 
    {540,1660}, 
    {580,520}, 
    {520,560}, 
    {600,480},
    {620,480}, 
    {540,540}, 
    {620,1600}, 
    {520,1660}, 
    {580,520},
    {520,1660}, 
    {600,1580}, 
    {620,1580}, 
    {540,1660}, 
    {600,1580}};

  for( int i = 0 ; i < 17; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);}}

void Footer ()
{int codes[3][2] = { 
    {580,1620},
    {540,38980},
    {8860,2120}};

  for( int i = 0 ; i < 3; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);}
  pulseIR(620);}

void IR(int codes[15][2]) 
{DeviceID();

  for( int i = 0 ; i < 15; i++) {
    pulseIR(codes[i][0]);
    delayMicroseconds(codes[i][1]);}  
  Footer(); }

void PowerButton()                             //Fixture power on/off toggle
{int codes[15][2] = { 
    {600,500},
    {600,500},
    {520,560},
    {600,500},
    {600,500},
    {520,560},
    {580,1620},
    {540,540},
    {600,1600},
    {520,1660},
    {580,1620},
    {580,1620},
    {520,1660},
    {580,1600},
    {580,520}}; 

  Serial.println("Power Toggle");
  IR(codes);}

void Night2()                                   //Fixture Initialize Night2 Mode
{int codes[15][2] = { 
    {600,1640},
    {600,500},
    {520,560},
    {600,1620},
    {600,1640},
    {520,560},
    {580,540},
    {540,540},
    {600,480},
    {520,1660},
    {580,1620},
    {580,500},
    {520,500},
    {580,1600},
    {580,1560}}; 

  Serial.println("Night 2 Mode Initialized");
  IR(codes);}

void Cloud2()                                         //Fixture Initialize Cloud2 Mode
{int codes[15][2] = { 
    {600,1580},
    {600,500},
    {520,1620},
    {600,500},
    {600,1600},
    {520,560},
    {580,480},
    {540,540},
    {600,560},
    {520,1660},
    {580,560},
    {580,1620},
    {520,560},
    {580,1600},
    {580,1640}};

  Serial.println("Cloud Cover 2 Mode Initialized");
  IR(codes);}

void FullSpec()                                  //Fixture Initialize Full Spectrum Mode
{int codes[15][2] = { 
    {600,1580},
    {600,500},
    {520,480},
    {600,1580},
    {600,1600},
    {520,560},
    {580,1600},
    {540,540},
    {600,560},
    {520,1660},
    {580,1580},
    {580,540},
    {520,560},
    {580,1600},
    {580,480}};

  Serial.println("Full Spectrum Mode Initialized");
  IR(codes);}

void DawnDusk()                         // Fixture Initialize Dawn/Dusk Mode
{int codes[15][2] = { 
    {600,1660},
    {600,1560},
    {520,480},
    {600,1580},
    {600,1600},
    {520,560},
    {580,500},
    {540,540},
    {600,560},
    {520,500},
    {580,1580},
    {580,540},
    {520,560},
    {580,1660},
    {580,1580}};

  Serial.println("Dawn/Dusk Mode Initialized");
  IR(codes);}

void Storm2()                         //Fixture Initialize Storm2 Mode
{  int codes[15][2] = { 
    {600,1660},
    {600,540},
    {520,480},
    {600,500}, 
    {600,1600},
    {520,560},
    {580,500},
    {540,540},
    {600,560},
    {520,1660},
    {580,1580},
    {580,1620},
    {520,560},
    {580,1660},
    {580,1580}};

  Serial.println("Storm2 Mode Initialized");
  IR(codes);}
 
#77 ·
No, it just fades between a dark blue to a dark purple. It's the darkest built-in mode without turning the fixture off. It would be easy to add an alarm to turn it off, but since the on/off is a toggle I've been hesitant to add it in case it misfires once.

You can independently control each color and store 4 custom colors, so I plan to match a custom color to the night2, then fade it down to off using the independent color control. It would be like Night2 > Custom purple > Fade > Fade > Fade > Fade etc, until it's all off. Probably starting the fade sequence at midnight. Then fade back on in the morning.
 
#78 ·
And Current has confirmed that they will use different IR codes starting with the next shipment of fixtures, so depending on where yours comes from it may be different. It should be pretty easy to crack the codes, provided they don't change the frequency. A new frequency would require an o-scope to determine and a different receiver. It's easy to tune the code to a different frequency one it's determined.
 
This is an older thread, you may not receive a response, and could be reviving an old thread. Please consider creating a new thread.
Top