The final program
The final program is meant to be used with a timer-clock for daily turn on and off. At night time, the Arduino is unpowered. At startup -and the Arduino has no sense of time- it begins to reach the destination-color of block 1.
The program uses 48 blocks, and every block is in the regular situation half an hour. Theoretically you can program 24 hours, but as the program is not accurate with time, it does not work to leave it powered. (The cycle will start over again, by the way. After block 48 the program returns to block one.) So, 48 blocks is the maximum, and for a normal daylight-cycle you won't need them all. Decide the length of time for your cycle, and let the timer-clock turn off the power a little later.
The blocks are visible in the program, and can be adjusted to your own fish tank:
Arduino Code:
if (block == 1) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 20000; brightness = 25; } if (block == 2) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 18000; brightness = 51; } if (block == 3) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 16000; brightness = 76; } if (block == 4) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 14000; brightness = 102; } if (block == 5) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 12000; brightness = 128; } if (block == 6) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 10000; brightness = 153; } if (block == 7) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 8000; brightness = 178; } if (block == 8) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 7000; brightness = 204; } if (block == 9) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6800; brightness = 230; } if (block == 10) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6600; brightness = 255; } if (block == 11) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6600; brightness = 255; } if (block == 12) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6600; brightness = 255; } if (block == 13) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6600; brightness = 255; } if (block == 14) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6600; brightness = 255; } if (block == 15) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6500; brightness = 255; } if (block == 16) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6400; brightness = 255; } if (block == 17) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 6200; brightness = 255; } if (block == 18) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 5000; brightness = 255; } if (block == 19) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 4000; brightness = 255; } if (block == 20) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 2400; brightness = 255; } if (block == 21) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 1800; brightness = 191; } if (block == 22) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 1400; brightness = 128; } if (block == 23) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 1000; brightness = 64; } if (block == 24) { newRed = 0; newGrn = 3; newBlu= 15; kelvin = 0; brightness = 0; } if (block == 25) { newRed = 0; newGrn = 2; newBlu= 12; kelvin = 0; brightness = 0; } if (block == 26) { newRed = 0; newGrn = 0; newBlu= 10; kelvin = 0; brightness = 0; } if (block == 27) { newRed = 0; newGrn = 0; newBlu= 7; kelvin = 0; brightness = 0; } if (block == 28) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 29) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 30) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 31) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 32) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 33) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 34) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 35) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 36) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 37) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 38) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 39) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; } if (block == 40) { newRed = 0; newGrn = 0; newBlu= 0; kelvin = 0; brightness = 0; }
If you fill out a kelvin value and brightness, it will replace the given newRed, newGrn and newBlu with the calculated (and calibrated) colors, taking note of the brightness. A brightness of zero causes all colors set to dark. On the other hand: as you can see with my moonlight in block 24-27, setting Kelvin to zero let the program use the red, green and blue from the same block. Those values will not be calibrated, the program uses the RGB colors you tell.
The given colors are interpreted as the destination color of that block. During the time of a block (normally half an hour), it will change the color equably from the color at the start of the block to the block-destination. For the first block, the start color is black (R:0, G:0, B:0). During the first block, the light slowly turns on and at the last moment of that block, the destination color is reached.
So make sure your timer runs one block longer that the last block with a value. In my example: block 27 is the last moonlight block. At the end of block 27, the lights are a faint color of blue. But at the end of block 28, the entire darkness is reached. Therefore, let your Arduino run for (used blocks + 1) x half an hour. So my program runs in 14 hours.
Just a few lines above the blocks, you will find the calibration-data:
Arduino Code:
//Led calibration //Use these to calibrate your leds, if you're not satisfied with the color white or to lower the max brightnes. //Use values between 0-255. All the values in the kelvinscale will be recalculated with this values. //Set each to 255 to not affect the values below. setWhitePointRed = 240; setWhitePointGrn = 181; setWhitePointBlu = 90;
Here you can enter the discovered value of neutral white light. (See page before)
To change the duration of a block, modify the blocktime var. It is set at 9000. On a normal base, the program uses timeticks of 0,2 sec, so 9.000 is equal to half an hour.
Minimal program adjustments needed
You can download the program below, wire everything up as written in "My Setup", but some adjustments are necessary:
- Make sure the I2C address of your OLED is the same as is used in the program. The I2C bus can be used for more devices at the same time, as everything has its own address. Use an I2C scanner if you can't get it work. (*)
- Set the right amount of LED's, as the 2812 protocol addresses them individually. Setting it too high will slow down the program (by calling LED's that doesn't exist), and setting it too low let part of your light hood not light up.
- Install all libraries needed. When you got an error during the compilation on one of the toplines, you'll be sure that one of the libraries is missing. (Used libraries: Adafruit Neopixel, Adafruit GFX, Adafruit SSD1306 and math.h. That last one is needed to use mathematical functions to calculate kelvin / RGB)
(*) Look in the program for the line below, and correct the address:
Arduino Code:display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
Download the Daylight simulator