Fade Aquarium led's with photocell code help?

First off id like to say im a newb to arduino and forums, who is sorry if the answer is on this forum already. I have done a cpl searches and didn't find the answer i needed.

Materials: arduino uno r3, 6 mosfets, photocell, 3 blue and 3 white 30W led aquarium lights

What I want to do: use an arduino to read a photocell and fade in/out blue/white led's at certain sun/moon brightness

Elaborated: I want to fade the blue on first in relation to the moon/sunrise brightness(sensorValue 0-399) and after the sun has brightened enough(say 9am ish, sensorValue 400-699) fade white on, then at the days brightest (12-1pm, sensorValue 700-999) blue and white will be full brightness, then back down again as the cycle continues,

i have successfully taken readings from my sensor and know the basic values for a 24hr cycle.
i have also successfully faded the lights at different speeds in/out with the fade example and mosfets.

BUT!!! i have no clue of how to write up a sketch that takes readings from photocell and fade up/down led's smoothly as sun rises and falls/clouds pass by.

ex: really bright moon=full blue, dull moon=half blue, morning=full blue/half white, noon=full all

i hope im being appropriately descriptive and any help/example codes would be just AWESOME!!!
thanks in advance!

I'm not a programmer but your situation seems perfect for this arduino tutorial on using both mapping of a value and the switch-case statements.

Good Luck,
SteveC

that example gets me close! but that only gives me 4 settings and the sensor HAS to be on the exact number specified..... as in

const int sensorMin = 0;      // sensor minimum, discovered through experiment
const int sensorMax = 1000;    // sensor maximum, discovered through experiment

void setup() {
  // initialize serial communication:
  Serial.begin(9600);  
}

void loop() {
  // read the sensor:
  int sensorReading = analogRead(A0);
  // map the sensor range to a range of four options:
  int range = map(sensorReading, sensorMin, sensorMax, 0, 3);

  // do something different depending on the 
  // range value:
  switch (range) {
  case 880:    // your hand is on the sensor
    Serial.println("dark");
    break;
  case 881:    // your hand is close to the sensor
    Serial.println("dim");
    break;
  case 882:    // your hand is a few inches from the sensor
    Serial.println("medium");
    break;
  case 883:   
    Serial.println("bright");
    break;
  } 
  delay(1000);        // delay in between reads for stability
}

so for this to work the way i wanted i would have to repeat.....

 case XXX:   
    Serial.println("XXXX");
    break;

about 999 times......
i need a way to define the ranges of the pwm output and photocell in, then get the output to be changed by the input accordingly.

led brightness=0-255
photocell in=0-999

any ideas?

hhuummmmm...... alot like a pot controlling a servo, fully linear. read pot, apply servo angle..... read photocell, apply pwm

this kinda worked sloppily.....

// Controlling a servo position using a potentiometer (variable resistor) 
// by Michal Rinott <http://people.interaction-ivrea.it/m.rinott> 

#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
 
int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin 
 
void setup() 
{ 
  myservo.attach(11);  // attaches the servo on pin 9 to the servo object 
} 
 
void loop() 
{ 
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023) 
  val = map(val, 0, 1023, 0, 180);     // scale it to use it with the servo (value between 0 and 180) 
  myservo.write(val);                  // sets the servo position according to the scaled value 
  delay(1);                           // waits for the servo to get there 
}

I get the general idea but I'm not clear about the details.

Do you want the fading in/out to be driven purely by the light level i.e. as the light level changes through a range your outputs change accordingly?

As far as handling clouds and so on, you could smooth your brightness reading over a few minutes or tens of minutes. An exponential decaying average provides a very convenient way to achieve that:

// the bigger the weight, the more smoothing will be performed
averageValue = ((weight * averageValue) + newValue) / (weight+1);

Do you want the fading in/out to be driven purely by the light level i.e. as the light level changes through a range your outputs change accordingly?

yes! exactly.

and no, i want the lights to dim as clouds pass by so no averaging or smoothing.

OMG!! IM GOING NUTS!

I have tried quite a few things and so far have this.....

const int sensorMin = 0;      // sensor minimum, discovered through experiment
const int sensorMax = 1000;    // sensor maximum, discovered through experiment
int blue = 10; 
int white = 11;


void setup() {


  pinMode(blue, OUTPUT);
  pinMode(white, OUTPUT); 
}

void loop() {
  // read the sensor:
  int sensorReading = analogRead(A0);
  // map the sensor range to a range of a kamillion zillion options:
  int range = map(sensorReading, sensorMin, sensorMax, 0, 1000);

  // do something different depending on the 
  // range value:
  switch (range) {
  case 0:   
    analogWrite(blue, 3);
    break;
  case 2:   
    analogWrite(blue, 4);
    break;
  case 4:   
    analogWrite(blue, 5);
    break;
  case 6:   
    analogWrite(blue, 6);
    break;
  case 8:   
    analogWrite(blue, 7);
    break;
  case 10:   
    analogWrite(blue, 8);
    break;
  case 12:   
    analogWrite(blue, 9);
    break;
  case 14:   
    analogWrite(blue, 10);
    break;
  case 16:   
    analogWrite(blue, 11);
    break;
  case 18:   
    analogWrite(blue, 12);
    break;
  case 20:   
    analogWrite(blue, 13);
    break;  
  case 22:   
    analogWrite(blue, 14);
    break;
  case 24:   
    analogWrite(blue, 15);
    break;
  case 26:   
    analogWrite(blue, 16);
    break;
  




  } 
  delay(100);        // delay in between reads for stability
}

it works ok so far but is "notchy" i guess, and sometimes locks up. any ideas?

Just a thought from another novice, take a reading of the sensor.
If the reading is between 0 - 299 map the reading to 0 - 255 and set your blue light pwm to that.

If the reading is between 300 - 1000 map the reading to 127- 255 and set your white light pwm to that.
// You don't want your white light to be completely off when the photocell is at 300 so you would have to adjust accordingly.

Does that make sense to you?

that sounds soo much easier but how?

now i have this working ok but WHEW! this is gonna take a while....

const int sensorMin = 0;      // sensor minimum, discovered through experiment
const int sensorMax = 1000;    // sensor maximum, discovered through experiment
int blue = 10; 
int white = 11;


void setup() {


  pinMode(blue, OUTPUT);
  pinMode(white, OUTPUT); 
}

void loop() {
  // read the sensor:
  int sensorReading = analogRead(A0);
  // map the sensor range to a range of four options:
  int range = map(sensorReading, sensorMin, sensorMax, 0, 1000);

  // do something different depending on the 
  // range value:
  switch (range) {
  case 0:   
    analogWrite(blue, 1);
    break;
  case 1:   
    analogWrite(blue, 1);
    break;
  case 2:   
    analogWrite(blue, 1);
    break;
  case 3:   
    analogWrite(blue, 1);
    break;
  case 4:   
    analogWrite(blue, 2);
    break;
  case 5:   
    analogWrite(blue, 2);
    break;
  case 6:   
    analogWrite(blue, 2);
    break;
  case 7:   
    analogWrite(blue, 2);
    break;
  case 8:   
    analogWrite(blue, 3);
    break;
  case 9:   
    analogWrite(blue, 3);
    break;
  case 10:   
    analogWrite(blue, 3);
    break;
  case 11:   
    analogWrite(blue, 3);
    break;
  case 12:   
    analogWrite(blue, 4);
    break;
  case 13:   
    analogWrite(blue, 4);
    break;
  case 14:   
    analogWrite(blue, 4);
    break;
  case 15:   
    analogWrite(blue, 4);
    break;
  case 16:   
    analogWrite(blue, 5);
    break;
  case 17:   
    analogWrite(blue, 5);
    break;
  case 18:   
    analogWrite(blue, 5);
    break;
  case 19:   
    analogWrite(blue, 5);
    break;
  case 20:   
    analogWrite(blue, 6);
    break;
  case 21:   
    analogWrite(blue, 6);
    break;
  case 22:   
    analogWrite(blue, 6);
    break;
  case 23:   
    analogWrite(blue, 6);
    break;
  case 24:   
    analogWrite(blue, 7);
    break;
  case 25:   
    analogWrite(blue, 7);
    break;
  case 26:   
    analogWrite(blue, 7);
    break;
  case 27:   
    analogWrite(blue, 7);
    break;
  case 28:   
    analogWrite(blue, 8);
    break;
  case 29:   
    analogWrite(blue, 8);
    break;
  case 30:   
    analogWrite(blue, 8);
    break;
  case 31:   
    analogWrite(blue, 8);
    break;
  case 32:   
    analogWrite(blue, 9);
    break;
  case 33:   
    analogWrite(blue, 9);
    break;
    case 34:   
    analogWrite(blue, 9);
    break;
  case 35:   
    analogWrite(blue, 9);
    break;
  case 36:   
    analogWrite(blue, 10);
    break;
  case 37:   
    analogWrite(blue, 10);
    break;
  case 38:   
    analogWrite(blue, 10);
    break;
  case 39:   
    analogWrite(blue, 10);
    break;
  case 40:   
    analogWrite(blue, 11);
    break;
  case 41:   
    analogWrite(blue, 11);
    break;
  case 42:   
    analogWrite(blue, 11);
    break;
  case 43:   
    analogWrite(blue, 11);
    break;
  case 44:   
    analogWrite(blue, 12);
    break;
  case 45:   
    analogWrite(blue, 12);
    break;
  case 46:   
    analogWrite(blue, 12);
    break;
  case 47:   
    analogWrite(blue, 12);
    break;
  case 48:   
    analogWrite(blue, 13);
    break;
  case 49:   
    analogWrite(blue, 13);
    break;
  case 50:   
    analogWrite(blue, 13);
    break;
  case 51:   
    analogWrite(blue, 13);
    break;
  case 52:   
    analogWrite(blue, 14);
    break;
  case 53:   
    analogWrite(blue, 14);
    break;
  case 54:   
    analogWrite(blue, 14);
    break;
  case 55:   
    analogWrite(blue, 14);
    break;
  case 56:   
    analogWrite(blue, 15);
    break;
  case 57:   
    analogWrite(blue, 15);
    break;
  case 58:   
    analogWrite(blue, 15);
    break;
  case 59:   
    analogWrite(blue, 15);
    break;
  case 60:   
    analogWrite(blue, 16);
    break;
  case 61:   
    analogWrite(blue, 16);
    break;
  case 62:   
    analogWrite(blue, 16);
    break;
  case 63:   
    analogWrite(blue, 16);
    break;
  case 64:   
    analogWrite(blue, 17);
    break;
  case 65:   
    analogWrite(blue, 17);
    break;
  case 66:   
    analogWrite(blue, 17);
    break;
  case 67:   
    analogWrite(blue, 17);
    break;
  case 68:   
    analogWrite(blue, 18);
    break;
  case 69:   
    analogWrite(blue, 18);
    break;
  case 70:   
    analogWrite(blue, 18);
    break;
  case 71:   
    analogWrite(blue, 18);
    break;
  case 72:   
    analogWrite(blue, 19);
    break;
  case 73:   
    analogWrite(blue, 19);
    break;
  case 74:   
    analogWrite(blue, 19);
    break;
  case 75:   
    analogWrite(blue, 19);
    break;
  case 76:   
    analogWrite(blue, 20);
    break;
  case 77:   
    analogWrite(blue, 20);
    break;
  case 78:   
    analogWrite(blue, 20);
    break;
  case 79:   
    analogWrite(blue, 20);
    break;
  case 80:   
    analogWrite(blue, 21);
    break;
  case 81:   
    analogWrite(blue, 21);
    break;
  case 82:   
    analogWrite(blue, 21);
    break;
  case 83:   
    analogWrite(blue, 21);
    break;
  case 84:   
    analogWrite(blue, 22);
    break;
  case 85:   
    analogWrite(blue, 22);
    break;
  case 86:   
    analogWrite(blue, 22);
    break;
  case 87:   
    analogWrite(blue, 22);
    break;
  case 88:   
    analogWrite(blue, 23);
    break;
  case 89:   
    analogWrite(blue, 23);
    break;
  case 90:   
    analogWrite(blue, 23);
    break;
  case 91:   
    analogWrite(blue, 23);
    break;
  case 92:   
    analogWrite(blue, 24);
    break;
  case 93:   
    analogWrite(blue, 24);
    break;
  case 94:   
    analogWrite(blue, 24);
    break;
  case 95:   
    analogWrite(blue, 24);
    break;
  case 96:   
    analogWrite(blue, 25);
    break;
  case 97:   
    analogWrite(blue, 25);
    break;
  case 98:   
    analogWrite(blue, 25);
    break;
  case 99:   
    analogWrite(blue, 25);
    break;
  case 100:   
    analogWrite(blue, 26);
    break;






  } 
  delay(10000);        // delay in between reads for stability
}

even though there is no change in brightness every 4 case's, if i just skip like case 0, case 5, ect, it locks up

I was thinking something like this:
Double check for typos.

/* not needed range should be 0 to 1023
const int sensorMin = 0;      // sensor minimum, discovered through experiment
const int sensorMax = 1000;    // sensor maximum, discovered through experiment
*/
int blue = 10; 
int white = 11;


void setup() {


  pinMode(blue, OUTPUT);
  pinMode(white, OUTPUT); 
}

void loop() {
  // read the sensor:
  int sensorReading = analogRead(A0);

// if our reading is low adjust blue 
   if (sensorReading < 299) {
      int blueBrightness = map(sensorReading, 0, 299, 0, 255);
      analogWrite(blue, blueBrightness);
}

// if our reading is high adjust white from halfway to full brightness
  if (sensorReading > 299) {
     int whiteBrightness = map(sensorReading, 299, 1023, 127, 255);
     analogWrite(white, whiteBrightness);
}

  delay(100);        // delay in between reads for stability
}

nice! works pretty good! added a serial monitor in and i had to toss in an else to get the white to turn off after reaching a brightness that activated it. dunno y though..... also set blue min to 1 so they never actually turn off all the way.

heres the code.....

/* not needed range should be 0 to 1023
 const int sensorMin = 0;      // sensor minimum, discovered through experiment
 const int sensorMax = 1000;    // sensor maximum, discovered through experiment
 */
int blue = 10; 
int white = 11;


void setup() {
  Serial.begin(9600);

  pinMode(blue, OUTPUT);
  pinMode(white, OUTPUT); 
}

void loop() {
  // read the sensor:
  int sensorReading = analogRead(A0);

  // if our reading is low adjust blue 
  if (sensorReading < 299) {
    int blueBrightness = map(sensorReading, 0, 299, 1, 255);
    analogWrite(blue, blueBrightness);
  }

  // if our reading is high adjust white from halfway to full brightness
  if (sensorReading > 299) {
    int whiteBrightness = map(sensorReading, 299, 1000, 0, 255);
    analogWrite(white, whiteBrightness);
  }
  else {
    analogWrite(white, LOW);
  }
  Serial.println(sensorReading);
  delay(100);        // delay in between reads for stability
}

still notchy though.... if i cant get it to fade smoothly with code then i will just wire in some big ass capacitors to smoothen out the transitions ...

~EDIT~ i changed delay from 100 to 1 and it smoothened out alot... now maybe some small caps

What do you mean by fade smoothly? Are the light levels changing that drastically every 100ms (lightening)?

If you see that your sensor is going crazy and reporting jumping values. Perhaps you can perform an average on several reads in the loop prior to the if statements to avoid it from drastically changing the analogWrite's:

You can use a chain of if/else statements to find which range your brightness is in and then calculate each output according to the algorithm which applies in that range. The map() function provides a convenient way to get a linear relationship between an input and an output:

if(brightness < 100)
{
    // 0 .. 99
    red = 255;
    green = 0;
    blue = brightness;
}
else if(brightness < 200)
{
    // 100 .. 199
    red = 0;
    green = map(brightness, 100, 200, 0, 255);
    blue = 255;
}
else if(brightness < 300)
{
    // 200 .. 299
    etc
}

That's a pretty good idea considering the sensor readings are exponential. Drops FAST after 6 so I can dial it in to truly match the light in and out.

Thanks! Im going to work on it later and see what's up.

ok, i added in the smoothing code, thanks alot histo!! this code now works flawlessly without capacitors needed for smooth fading.....
now i want to add a button that makes all lights full brightness and when pressed again resumes the previous operation.

heres the code.......

/* not needed range should be 0 to 1023
 const int sensorMin = 0;      // sensor minimum, discovered through experiment
 const int sensorMax = 1000;    // sensor maximum, discovered through experiment
 */
int blue = 10; 
int white = 11;
const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average

int inputPin = A4;


void setup() {
  Serial.begin(9600);
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings[thisReading] = 0;    
  pinMode(blue, OUTPUT);
  pinMode(white, OUTPUT); 
}

void loop() {

  // subtract the last reading:
  total= total - readings[index];         
  // read from the sensor:  
  readings[index] = analogRead(inputPin); 
  // add the reading to the total:
  total= total + readings[index];       
  // advance to the next position in the array:  
  index = index + 1;                    

  // if we're at the end of the array...
  if (index >= numReadings)              
    // ...wrap around to the beginning: 
    index = 0;                           

  // calculate the average:
  average = total / numReadings;         
  // send it to the computer as ASCII digits
  Serial.println(average);   



  // read the sensor:
  int avarage = analogRead(A4);

  // if our reading is low adjust blue 
  if (average < 199) {
    int blueBrightness = map(average, 0, 200, 1, 10);
    analogWrite(blue, blueBrightness);
  }

  // if our reading is high adjust white from halfway to full brightness
  if (average > 199) {
    int whiteBrightness = map(average, 170, 1000, 0, 255);
    analogWrite(white, whiteBrightness);
  }
  else {
    analogWrite(white, LOW);
  }

  delay(1);        // delay in between reads for stability
}

i will work on the button later and post a sample up.... till then any ideas?