Slider 01 Slider 04 Slider 03 Slider 02

Wooden marble calculator

Definitely not a small calculator. In inches, it has a height of 23 inch, is 18-inch-wide and 10-inch deep. For fans of the metric system: a height of 58 cm, 46 cm wide and 25 cm deep. Operates with values up to 1024, and can count and multiply, as multiplying can be seen as repeated counting. (5 x 7 becomes 7+7+7+7+7)

Does not use batteries or a solar panel. Does not use any power source at all, except gravity. The numbers are represented with marbles, as well the input values as the result.

I found an example of this principle on the web and I decided to build one myself. With some modifications, as a mechanical calculator needs the look of a machine. And as it uses no electricity, the machine may have an appearance as it could have been used in the 19th century.

(As one goal of the machine was to make people familiar with binary numbers, there is much attention for setting up the numbers)

The movie above does not give any clues away. The movie below will show you the entire principle:


Building the machine


Most of the building part is easy and can be understood by looking at the pictures. There are only two parts with a little higher range of difficulty: the flipflops and the mechanics to operate the sliders.

At first, the flipflops were entirely made of wood, but reacted a little unpredictable. With sums like 3 + 3, the flipflops need to act very accurate, as the flipflop on line 2 must deal with 3 marbles: one is stored in its memory, one as handed over from line 1, and one comes from the upper slider. To solve the inaccuracy, I added some aluminum strip on top. After this adjustment, all operations became accurate.







The sliders

handle01 handle02

The other part with a higher level of difficulty are the sliders and the handles to move them. Inspired by the old-fashioned cash registers, I’d like a handle for operating the machine. As there are two sliders (a top slider to make it easy to place a value, and a result slider to hold the marbles on the sum-line) which work together, I’ve used two handles: a “count-up” handle, which adds the marbles to the central part of the machine (you can call it memory), but also opens the lower slider to let marbles pass which are no longer needed in the memory. As you store two marbles after each other on the row with value “1”, only one marble on the row with value “2” is needed in memory: the other falls down, and as the result slider is open, it won’t stay on the sum-line but falls down to the marble reservoir. The second handle shows the result, by closing the lower slider, and turns all flipflops to their start position. If a flipflip was holding a marble, it will fall down, and remain on the sum-line. There you can read (or count) the result of the sum.

As the upper slider is always closed when no handle is used, it has a spring that automatically close the slider. The lower slider remains in its last position. (Actually always open, except when a result must be shown)

The movement of the handles is transferred by nylon rope and handmade pulleys. Pulleys are not necessary, but an easy way to keep the rope where it belongs. As the accuracy is not 100% (all had been sawn by hand, I have no CNC router), it turned out to be a little problem to turn all flipflops to their original state. To solve that I used some thick copper-wire between the hinging unit and the plug of the flipflops.




Photoalbum wooden marble calculator_
The first parts of the lanes

Photoalbum wooden marble calculator_
These blocks align and slow down
the marbles.

Photoalbum wooden marble calculator_
Use solid wood, as there will be a weak

Photoalbum wooden marble calculator_
Something need some sanding...

Photoalbum wooden marble calculator_
The flipflops were printed on paper and
glued on the wood.
Photoalbum wooden marble calculator_
All flipflops with their reset pin glued in.

Photoalbum wooden marble calculator_
And with their axes attached.

Photoalbum wooden marble calculator_
Assembling the lanes.

Photoalbum wooden marble calculator_
And the main deck contains all parts.

Photoalbum wooden marble calculator_
Drawing the sliders.

Photoalbum wooden marble calculator_
Sawing of the holes

Photoalbum wooden marble calculator_
The most down lath is meant to move to
the marble reservoir.

Photoalbum wooden marble calculator_
The resultslider is not placed, but you
can see the slit ment for it.
Photoalbum wooden marble calculator_
Front side view

Photoalbum wooden marble calculator_
The making of the part to reset the
Photoalbum wooden marble calculator_
The marble dispenser.

Photoalbum wooden marble calculator_
The handles.

Photoalbum wooden marble calculator_
The flipflop-reset mechanism.

Photoalbum wooden marble calculator_
Decorating the front panel.

Photoalbum wooden marble calculator_
It's a combination of wood burning and
some paintwork.
Photoalbum wooden marble calculator_
The inside view of the fixation of the
Photoalbum wooden marble calculator_
The attached and unpainted handles.

Photoalbum wooden marble calculator_
The springs to reset the handles.

Photoalbum wooden marble calculator_
The disks will be used to attach the rope
to operate the sliders.
Photoalbum wooden marble calculator_
The "reset-your-flipflop-system".
Photoalbum wooden marble calculator_
Wheel of a pulley.
Photoalbum wooden marble calculator_
One of the pulleys almost ready.
Photoalbum wooden marble calculator_
As they do not move much, I used
aluminum busses.
Photoalbum wooden marble calculator_
The other side of the axis ends in a hole
in the outer case of the calculator.
Photoalbum wooden marble calculator_
Pulley one is ready!

Photoalbum wooden marble calculator_
The second one also...

Photoalbum wooden marble calculator_
And the corner-pulley is also ready.

Photoalbum wooden marble calculator_
Taking over the numbers on a piece of
wood with a burner.
Photoalbum wooden marble calculator_
Placing the numbers on the front.

Photoalbum wooden marble calculator_
The upper numbers are burned on a very
thin piece of wood.
Photoalbum wooden marble calculator_
Flipflops attached, and checked for
smooth movement.
Photoalbum wooden marble calculator_
Attach the rope between the disks and
the sliders.
Photoalbum wooden marble calculator_
Calibrating the "flipflip-reset-system" by
bending the copper wire.
Photoalbum wooden marble calculator_
The upper disk operates both sliders,
the lower only the result slider.
Photoalbum wooden marble calculator_
Complete overview from the inside.
Photoalbum wooden marble calculator_
And the outside!

Domotica at home

Home automation for only $21.13! Sounds too good to be true, and actually you will need something more: 433 MHz power switches (Dutch: klikaanklikuit modules) to use the wireless opportunities. But without, you still can use 8 relays with your cellphone or any device with internet.

A few months ago, a friend came to me for some help with his home-automation wish: control everything in his apartment with only one remote. So we started this project.


The list of needed parts:

1 Arduino Mega clone $ 7.10
1 ESP 8266 WIFI module  $ 1.24
1 set RX / TX 433 mhz. $ 0.37
1 block with 8 relays $ 3.88
1 power-unit $ 4.41
1 OLED screen $ 3.23
1 push button $ 0.71
1 small piece of PCB $ 0.18


And, of course some scrap wood and other materials. I used plexiglass for my casing. I like to see the connected parts, but at the lower level it's no weak current: depending on your country, the relays will switch 110-230 volts. So the entire package I made will be stored in a wooden box once its operational.


What can it do?

After the unit is powered, it will connect to a WIFI network. The OLED screen looks pretty small, but can be read very easily. Once connected, it shows the IP address where you can find it's control center. It's a local address, so only available when you are connected to the same network. Of course it's possible to configure your access point to make it visible from outside your network, but the whole world gets the ability to switch off your coffee machine. So be warned...

Once your cellphone, tablet or laptop has loaded the website, it can control everything connected to the relays and the radio transmitter. The website uses AJAX for sending the commands, so there is no delay for reloading the website every time you turn a switch.


Choices and decisions

mega mini

The Arduino Mega and the Wemos D1 mini

We started this project first with a Wemos D1 mini. It has some major advantaged above the Arduino Mega:

  • It's very small
  • It's very cheap (below $3.00)
  • It has lots of memory to store vars.
  • There is no need for an external WIFI-unit: it is embedded on the circuit board.
  • Using WIFI is very easy, as this kind of board is a real IOT board.

We discovered also some disadvantages:

  • It has only a few pins (9) for input/output, and some are still in use by the Serial line or the WIFI.
  • Because we needed all pins, the Serial monitor could not be used for tracing purposes. Programming and debugging became a little slow due to the lack of this kind of monitoring.

Some problems can be solved by using an extension board. You offer one or two pins, to get four till eight in return. We decided to switch to an Arduino Mega clone because of the next advantages:

  • More sets of RX / TX serial ports. That makes it easy to remain connected to your Arduino IDE (and serial monitor) while using another serial port for the WIFI simultaneously.
  • Lots of input/output pins.

Beside the advantages, there are also some disadvantages. The main problem is the small amount of memory (8 kb for storing vars) and the combination with the ESP8266 WIFI unit. The connection between them needs to be read as text (char or strings), and you even have to store/collect messages to interpret them once they're completed. And last but not least: the website itself needs to be stored on the Arduino also. More text to store.


OK WIFI DISCONNECT ets Jan 8 2013,rst cause:2, boot mode:(3,7) load 0x40100000, len 1856, room 16 tail 0 chksum 0x63 load 0x3ffe8000, len 776, room 8 tail 0 chksum 0x02 load 0x3ffe8310, len 552, room 8 tail 0 chksum 0x79 csum 0x79 2nd boot version : 1.5 SPI Speed : 40MHz SPI Mode : DIO SPI Flash Size & Map: 8Mbit(512KB+512KB) jump to run user1 @ 1000
Ai-Thinker Technology Co. Ltd. ready

Above the response after a given AT+RST command (a reset)

The storage of text (Strings) is complicated on an Arduino. It's the only var with unknown memory usage when it's declared. Besides that, you clone (and double the usage of memory) very often when working with strings: pass it through a function, edit it, etc.

Once your memory is filled up, your Arduino will behave strange: resets without warning, program crashes, unexpected return-values from functions, and almost every time no signals from the serial ports anymore...

Connecting the modules

For this project there will be 5 modules connected to the Arduino. Most of the pin assignments are not critical. In other words: most of the destination pins can be changed, but a modification of the program will be necessary. In my case, I've decided to choose the pins on the short side of the PCB, to make shorter connections and to prevent the wires to mess up.


connect esp8266 arduino

The ESP8266

This module is used to connect your Arduino to the internet, or in this case: to your local network. As mentioned above, it communicates with two serial lines (RX and TX). This is the only module needing 3.3 Volt, instead of 5.(!) That means that not only the VCC should be treated in a different way (do not connect it to your 5V power supply, connect it to the 3.3V pin of your Arduino), but also you need some resistors on the RX line to lower the voltage.

It's also mentionable that this WIFI module only uses the 2.4 GHz band and is not able to connect to the modern 5.0 GHz band. As far as I can see that won't be a problem right now, as I don't know one single router with only the 5 GHz band.

In this project we use pin 18 and 19 to connect to the Arduino. Those are not critical, as an Arduino has four sets of serial ports:


arduino communication ports small
The communication pins on the Mega

RX 0 and TX 0 have been set aside, as they will be used for program uploading and the serial connection (with the monitor, plotter and IDE) on your computer.


The other ones are not in use. I do not know if they are exactly interchangeable, but I've chosen RX1 and TX1. If you want to change to another set of lines, change the program, and replace all "Serial1." commands to "Serial2." (or "Serial3." of course).






The OLED I2C SSD1306 12864 LCD

connect oled arduinoThe first time I received one of these OLED modules, I got surprised by the fact that its size is no problem at all! As they are really small (below 1 inch), you would expect the need of glasses to read them. But actually four lines of text is no problem at all.

The old modules (without I2C) used lots of wires (4 or 8 data lines), but the I2C versions are easy. GND, VCC and a SCI and SDA are needed.

Is the pin configuration critical? An Arduino Mega has one set of SCI and SDA pins. These function like a bus -the I2C bus-. Therefore it is not necessary to change pins when you want to add something more on that bus, devices can share a bus. Communication will be separated by the use of an address. That means that you'll have to check the address of your screen and correct it in the program. (More explanation in the check your module section)


The FS1000a transmitter

connect fs1000a arduinoNormally you'll buy them as a set, and even you don't need the receiver in your final setup: don't throw it away. You will need it to get the codes from the remote controls of your wireless switches. As you can see, there is a small hole on the FS1000a with the description ANT near it. You can add an antenna to it when the unit cannot reach the desired distance. Tests over here showed no problem over 10 meter, so I did not attach one.



I used pin 53 on the Arduino, but every pin can be used. You only have to change the program on this line:

#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
#define pinTX 53

Change the 53 to another free pin when desired.

And last but not least: a pushbutton

connect pushbutton arduinoThis is a button which only creates a circuit during the push. It is meant as a wake-up-button for the screen, as I do not want it to display info 24/7. Once the button is pressed, it lights up de display for 60 seconds. As you may know, the button needs to be connected with a pull down resistor.

Another alternative is to use a switch (on / off), and connect it on the 5V line of the OLED, to interrupt the circuit, and the OLED is turned off for real. (Notice that the pushbutton system does not interrupt the power, the program stops using the screen)




Checking the modules

It can be really frustrating when you put everything together in a nice casing, with all wires cut to the desired length, and you discover problems... So I suggest to test all modules separate and together before wiring if permanent. Use a breadboard and some Dupont cables to wire it up, and use the test programs to make sure everything works fine.

Checking the ESP8266

After wiring it up, use the next program when connected to your computer. Your serial monitor should tell you the results of an attempt to connect to your WIFI network.

void setup() {
Serial.begin(9600);     //<--This is the connection with your computer.
  Serial1.begin(115200);  //<--This is the connection speed with your ESP.
  // WiFi SSID and Password
  String SSIDstring = ("#####");            //Replace ##### with your network name / SSID
  String PASSstring = ("#############");    //Replace ########### with the password of your network
  useESP("AT+RST\r\n", 2000);
  useESP("AT+CWMODE=1\r\n", 2000);
  useESP("AT+CWLAP\r\n", 8000);
  useESP("AT+CWJAP=\"" + SSIDstring + "\",\"" + PASSstring +"\"", 6000);
  useESP("AT+CIPSTATUS\r\n", 2000);
  useESP("AT+CIPMUX=1\r\n", 1000);
  useESP("AT+CIPSERVER=1,80\r\n", 1000);
  useESP("AT+CIFSR\r\n", 1000);
void loop() {
String useESP(String command, const int timeout) {
  String response = "";
  Serial.println("The Arduino sends the next command to the ESP8266:");
  Serial1.print(command);   //<-- This is the real command to send to the ESP
  Serial.println("Waiting for response...");
  long int time = millis();
  while( (time + timeout) > millis()) {
    while(Serial1.available()) {
      char c =;
      response += c;
  return response;

The program communicates using serial 1 (TX1 and RX1) with the ESP8266. The program will show you the given command, and the response of the ESP8266.

Under normal circumstances, you should see the reset (RST) command, after which the ESP generates a summary. You also see a list of networks in your area, and the program tries to connect to your network. If that is possible, it will show you the given IP address. (a reference of usable commands can be found here)

When it does not connect, you still will get output on your monitor. (Otherwise your Arduino cannot communicate with your computer). If there is no response from your ESP8266 at all:

  • No response at all can also be a result from a wrong baud-rate of your serial connection with the computer. (duh....) Both on 9600?
  • Try a different power supply. On the web you can find problems with unstable power. You can also test with a power bank (has a USB connector itself!), a cellphone charger (idem) or even battery packs. (When you feed the Arduino 5 V through USB of a 5V line, it generates 3.3 for the ESP itself)
  • An unstable kind of power can be solved with the use of a capacitor between 3.3V and ground. When there is a (little) noise on the power lines, most modules will work, but not the ESP8266. Even when its power led is on.

When there is response, but totally unreadable, too short or the word "busy..":

  • Try another bitrate (baud) for the communication on Serial1 (= with the ESP). Maybe your version of firmware has a different baud rate.
  • Shut down the power for some time. Every time you reset your Arduino / upload a new program, the ESP does not reset by itself. (it remains powered)  In some cases, it is waiting for something (like a close command or a website to send of a given number of characters) and shall not take new orders before the current task has been finished.

Testing the FS1000a

To test the FS1000a, we need 3 more things:

  • Some device or switch which uses the 433 MHz protocol for input. A big part of our project are the wireless switches, and our project is going to replace it's remote controls.
  • We need the remote controls itself, to learn the code to be broadcasted.
  • Therefor, we also need the 433 MHz receiver, but as we bought the RX and TX as a set...

080408 to arduinoAttach the receiver to 5V and ground, and connect one of the middle two data-pins to Arduino pin 2. You will nead an extra library if for your Arduino, so make sure RC-Switch is installed (of not, get it!).

The library of RC-Switch can handle the protocol we need. But not all power outlet sockets use the same protocol. It will be possible that you need another library of other hardware for your wireless switches, but the "klikaanklikuit" devices over here work.

Once you've setup the breadboard. just start the "ReceiveDemo_Advanced" script on your IDE. (Examples > RC-Switch > ReceiveDemo_Advanced)

Now you can use one of your remotes (maybe disable the receivers before...) and take a look at the information on your serial monitor:

Decimal: 3700159 (24Bit) Binary: ‭001110000111010110111111‬ Tri-State: not applicable PulseLength: 306 microseconds Protocol: 1

Raw data: 9536,268,900,280,912,840,320,864,308,868,304,280,896,292,884,284,880,308,872,884,288,876,300,864,332,268,900,848,320,272,908,848,336,840,324,860,312,276,908,264,908,852,328,844,100,16,92,444,512,

Maybe I take some risk by showing you one of my codes, because everyone with an Arduino / FS1000a combination can broadcast a "3700159" code of 306 microseconds in front of my house to activate the SoundBlaster radio...

Learn all codes from your remote(s). As you can see the pair of codes (on and off for one device) are almost identical, only the "off"-code is one lower. (In my case: you can turn the SoundBlaster off with 3700158)

Now we take our breadboard again, and setup for the transmitter: de FS1000a. Wired as mentioned in the section before, you can run the next test:

#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
#define pinTX         53
#define pulseLength   306
#define bitLength     24
#define protocol      1

void setup() {
void loop() {
  mySwitch.send(3700159, bitLength);
  mySwitch.send(3700158, bitLength);

With this script, the power outlet socket will be turned on and off every four seconds.


  • If you can receive the codes (with the RC-Switch library and the receiver) you would be able to send codes. If you can't receive, there is a possibility of the use of a protocol which cannot be handled by RC-Switch or this hardware.
  • If you can receive codes, but sending them won't let anything happen and codes seem to change often... You may deal with a system with "rolling code". As a measure of security, some devices use a system with encryption / calculated keys. As long as you cannot get your hands on their algorithm, it won't be possible to control that kind of devices.
  • When their seems to be an unpredictability in your results, there may be interfering factors or a too big distance. Remember, it is possible to add an antenna on the transmitter!

Testing the OLED I2C SSD1306 12864 LCD

The OLED is connected to two special pins: the I2C-bus. As in computers more devices can share one bus, because communication will use addresses. So you need to find the address of your screen first. That can be done with an I2C Scanner. Once you've got it, you can test your screen with the Adafruit SSD1306 library example. (Make sure you also install the Adafruit GFX library) If you'll get the warning to fix your SSD1306 library, open up the Adafruit_SSD1306.h file in your editor. The only line uncommented should be the line with your screen resolution:

SSD1306 Displays
The driver is used in multiple displays (128x64, 128x32, etc.).
Select the appropriate display below to create an appropriately
sized framebuffer, etc. SSD1306_128_64 128x64 pixel display SSD1306_128_32 128x32 pixel display SSD1306_96_16 -----------------------------------------------------------------------*/
#define SSD1306_128_64 //<<-- My resolution, this line is oncommented
// #define SSD1306_128_32 //<<-- Not my resolution, this line is commented
// #define SSD1306_96_16 //<<-- Not my resolution, this line is commented

(Normally, this file can be found on your hard drive: users\#username#\documents\Arduino\libraries\Adafruit_SSD1306\ )



Testing the relay-bank

As you wired as mentioned before, you can use the program below to test your relays. When using for testing purposes, we do not attach the relays to outlet sockets. The relays have LED's on board, so testing is possible without the dangerous alternating current from your wall socket.


void setup() {
  for (int i = 22; i < 36; i = i + 2){
    pinMode (i, OUTPUT);
    digitalWrite (i, HIGH);
  } void loop() {
  for (int i = 22; i < 36; i = i + 2){
    digitalWrite (i), LOW);       //<-- Turn relay ON
  for (int i = 22; i < 36; i = i + 2){
    digitalWrite (i), HIGH);      //<-- Turn relay OFF

 Running these code let all relays go on and off.


  • This is the only part with both alternating current and weak current(!), and the PCB has a jumper for more safety: it is possible to operate the relays with another power supply to isolate the Arduino more. In this example we leave the jumper on JD-VCC. So make sure your jumper is at the same position.


Testing the push button

Although there is nothing spectacular about testing a pushbutton, I will test it. When having troubles with the main program, there is nothing more frustrating than "things you would expect to work, but they didn't". So use the button example in the IDE (examples > 2.0 Digital > Button) to check your connections.


The main script

The main script can be used after some adjustments. The next data will be different for everybody:

  • The name and password of your WIFI network.
  • The (amount of) devices you want to control.
  • The grouping of the devices (on four tabs).
  • The way you want to control them (with relay of wireless).
  • The available radio codes to turn things on and off.

Besides those points, when you can work with HTML it is also possible to change the website, add or remove tabs, change the tab-icons or the turn on and off buttons. On the next page of this article you will find information about the website, as most is hidden in a JS file.

The devices

Make a list with all devices you want to control, and sort them as you want to see them on the website (first device is first item on first tab, second device is second item on first tab, and so on).

  • Enter the amount of devices in the program.  (const int devices)
  • Add the names (in the order meant above) between quotes and seperated by comma's to the const String deviceNames[].
  • For every device, add the tab number to const int deviceTabs[]
  • Add the destination. What needs to be used when the button of that device is pressed? Destination 1 - 8 are relays, 11 and higher are wireless codes to be broadcasted. (const int destinations[])

For all wireless devices, two codes are needed. One to turn off, and one to turn on. If you use devices which use only a single code like a pushbutton (door openers for example), add the code twice: once on the list of codes to turn on, and once on the list of codes to turn off.

The setup part of the RC Switch contains the pulseLength, which maybe can be different from mine. The pulselength of your wireless switches can be found with the test-program "ReceiveDemo_Advanced" mentioned on the page before.

The OLED screen is bus connected, and will only be able to work when the correct address had been entered in the program:


display.begin(SSD1306_SWITCHCAPVCC, 0x3C);               //<-- The address(0x0C) can be different on other OLED screens.


Besides that, run the test-program at least once. It will also warn you when your library "Adafruit_SSD1306.h" needs an adjustment for your resolution. See the module-checking page..


Dwnldicon Download the Home Automation script


The script serves a website, which has dependencies to three other files:

    This is the CSS file for the entire website.
  • https://ajax/
    This loads jQuery, which is used in the next file. It doesn’t need to be stores on an own server, as it is allowed to link directly to the Google Apis.
    The JavaScript file does the big part: This file not only contains the functionality, it is also necessary for building up the HTML and building up the images (all SVG)

I can imagine you need to change ha.js, as it contains the images. And most people won’t use the same TV, light, bed and door icon I do. So you need to have access to a web server to store ha.css and ha.js. On the next page, you can find the zip files of these two files.

For testing purposes or “just wanting the same version I have”, you can use the ones stored on the 2muchtime server. (Link to the addresses above, not to their zip-file)

And off course: using your own files means you have to change the script on your Arduino: recplace the URLs in the string of the website with your own locations.


The website



To reduce the risks, the program sends a very small website, about 450-500 characters (depending on the devices):

<!DOCTYPE html>
    <link href="" rel="stylesheet" />
    <script src="https://ajax/"></script>
    <div id="c" style="display:hidden">
      2muchtime Domotica,*,Television,Moodlight,Light near window,TV light,*,Moodlight bed,Bedside table light,*,Desk light,Light at backside,
      General,Light above table,*,Front door
  <script src=""></script>

Above the website as will be server by the Arduino to your browser.


The website has dependencies to three files: jQuery, a CSS file and a JavaScript file. All will be served from another server.

The JavaScript file is used for the next purposes:

  • It reads the value of the <DIV> tag, and separates that into a title, and all devices. A * is the separation character to go to the next tab. Finally it removes the content of the div.
  • It builds up the entire website by adding the title, the tabs and a responsive square for every device with a power-on and power-off button.
  • It contains all six images, which are actually SVG images.
  • On a window resize, it will act responsive and recalculate the location of buttons.
  • It handles the tab-navigation.
  • It contains a little AJAX to send information (a button press) to the server without a page reload.

The files can be found here:

Dwnldicon Download the Javascript file (zip)


Dwnldicon Download the CSS file (zip)

DIY Arduino daylight sim

A daylight simulator for fish tank, completely adjustable to any biotope. Can produce Kelvin colors, as well as RGB colors. I've done this project twice. In 2014, with an Arduino and a LED PWM dimmer shield. Today, LED's with the 2812 protocol become more popular, as they have their own PMW dimmer for every single led. You can control hundreds of LED's without an extra shield. The program on the Arduino Mega can handle both systems, and with a little tweak every RGB LED driver with the capability of being controlled by an Arduino will work.


For almost 10 years now I have a small fish tank (60 liter / 16 gallon) on the place where once my TV stood. No bad deal as the TV was never used, and "the big dark square" caused by it was not an asset to my interior. The tank has a couple of small fish and shrimps. And lots of snails. For the lightning, I switched from tubes to white LED's and finally RGB LED's. The reason? This system offers me "a different kind of view" almost every (couple of) hour. The color of light can quite change the view, as some colors let things light up, as other colors just ignore them. The spider wood -brown- does not stand out in the regular daylight (6500 K), but when the light gets warmer (yellow - red) it takes a key role in the tank.

People who like it, can try to rebuild this project. It's much cheaper than the light computers sold in shops. Depending on your choices, you can calculate the possible amount of money needed on the third page. The page before (actually the next page right now) contains some information on LED's, and I may say those were learning points for me. 


LED's talk about LED

LED's are a very unique source of light. And before building up this daylight simulator, it's better to take note of the pro's and cons of them....

Off course there are different kind of LED's with all their own characteristics. The LED's I am talking about are RGB LED's, and more specific: the ones sold as LED strips.


The quality of light

As RGB LED's are actual 3 LED's in one housing, they do not really produce white light: they blend red, green and blue to create the desired color. These three colors are rather pure: their spectrum is small. On the left side, the spectrum of an RGB LED, right the spectrum of a light tube for fish tanks. The white line in both spectra shows the spectrum which is needed for photosynthesis.

 Spectrum of a TLspecled











Blending the light with an RGB controller cannot fill-up the gaps: Parts of the spectrum which are absent cannot be repaired. The TL on the right does a better job, although it's also not perfect. So, if your tank contains plants which need of good light, you can consider using tube lights for at least a couple of hours a day.


I want to use LED's for saving electricity

On the web, you can find manufacturers with nice stories about high efficiency, lots of light... The small RGB LED's on strip do not have a high rate of efficiency, and the promised light output may be a little lower. The movie of my tank is made with 300 RGB LED's on a strip, of the type WS2812 IC 5050 RGB LED, with the specs below:

Color Wavelength Luminous intensity Current Voltage mW
Red 620-630 nm 550-700 mcd 20 mA 2.0 V 40 mW
Green 515-530 nm 1100-1400 mcd 20 mA 3.1 V 62 mW
Blue 465-475 nm 200-400 mcd 20 mA 3.3 V 66 mW

As my white point seems to be red: 100%, green:  71%, and blue: 35%, every LED uses 40 + 44 + 23 = 107 milliwatt. For all LED's together, we are talking about 32 Watt. And the level of light is definitely below the light of one 18-watt TL.


I want to use LED's for saving money

LED damage after 10.000 hrs The lifespan of a LED is very long. But actually, lifespan is the wrong term. Most of the time, LED's do not stop working, they just shine less bright. Technically they are not broken, and their lifespan hasn't ended yet. But still they become unusable. The picture shows two led strips (not RGB, white LED strips). One is unused, the other has been used for about 10.000 hours (3 years).

Nowadays, LED's become cheaper and cheaper. But for this project, you need some things more, all with their own lifespan. And as I mentioned above, you won't save money on electricity either, I guess. 

LED systems like this have the advantage like all DIY projects that they have a high rate of replaceability: one thing damaged, one thing replaced. My old light hood of the tank was made for tube light, and had its starter unit sealed in. Unreplaceable. Therefore, a broken starter-unit charged me for almost $ 80.00.


Other points about LED's

As I am a DIY person and not a high skilled electrician, I prefer the fact that my light hood only uses 5 Volts. (or 12 Volts, depending on the kind of strips) Besides that, I also like the fact that the temperature in the hood does not raise to destructive levels anymore. And off course the biggest advantage: the customizable colors. Even if you use a standard RGB controller and 5-10 meters of strip with no color changing at all: you can change the appearance of your tank with one button press. With tubes and other lightsources you even get surprised when you first light them and the color is a little "different as expected", Get used to it, you will see that color for long times.

Buying LED's

As most of the TL lights have the same efficiency, many tank-owners think about "watt per liter/gallon". Nowadays there are so many light sources with different specifications, that it becomes difficult to compare them. What about lux, lumen, candela and mcd? Take a look at the picture below. The red and white desk light have the same intensity of light, and blue and white have the same size of beam... So, all are different.

Lumen and Lux


Talking about lux is talking about intensity. As you can see, the white and the red light have the same intensity. Because of its wider beam, red produces more light, but still has the same intensity. Therefore, Lux is impractical to determine the amount of light sources needed.


Candela is the luminous intensity in a given direction per steradian. In other words: the total amount of light within a certain direction (a steradian). This is actually also a quantity of light-intensity. In the picture, white and red have the same amount of Candela, blue has more.


One MCD (micro Candela) is 1/1000th of Candela.


Lumen tells you something about the total amount of light which emits from the light souce. In the example above, red and blue have the same amount of Lumen, white has a lower amount. The fact that blue has a smaller beam causes its beam to have a higher intensity. For your tank, you need to use the amount of lumen to decide the amount of light sources. It is possible to calculate lumen if you know candela or lux, as you also know the radiation angle of the source. Conversion can be done on many sites on the internet (click).



Different kind of set-ups

As most people with the fish tank syndrome, I like to limit the use of technics, and when I use it, I'll try to make it invisible. In this case, I made a small remote (45 x 30 x 8 mm). That is the only visible part. My Arduino itself and the power supply have been put away from the water, and stay out of sight. (Some people think the small wooden remote is the light computer, but unformtunately that's not possible)

The big choice to make is "what to use as a RGB LED driver", as can be seen in the image right:

setup01This version has one central LED driver. Depending on the size of your tank, it must be able to handle 100s of LED's. The version I have, used 12 V RGB LED strip, and when the driver was powered, it also powered the Arduino with 5 Volt. Depending on the LED strip (common anode or common cathode) there is a central ground or +12V to the strips, and three wires for the colors. The remote has a small cable with 5-7 wires in it (I used an old PC cable). The OLED screen uses 4 wires (two wires for the I2C bus, and a +5V and a ground), the button 1, 2 or 3. (The button needs a connection to an Arduino pin, a +5V and a ground for a pulldown resistor). It is possible to share the power lines with the OLED, but if you have enough wires in your cable: let both devices have their own power, to reduce the risk of interference. If you have a cable with 6 wires, then I suggest to share the +5V, and give the button its own ground.

The advantage of this setup it the possibility to use cheap LED's. Those strips with the world-famous 5050 LED's are a very cheap solution. However, you need a driver (or more drivers) to control them. That driver probably is the most expensive part of your setup.


setup02On the other hand, you can use RGB LED strips with the 2812 protocol. Those LED strips are more expensive, but every LED on the strip has its own driver embedded. It used tree wires: +5V, ground and Din (data in) and do (data out). The do of every single LED is connected to the din of the next LED. With only 3 wires, these strips have individually addressable LED's! This program does not make use of that property, but if fact it's possible to create different zones with different light. (Moonlight only at the front? More light in zones with critical plants?)

At first I had some reservations. At what speed do all those small controllers pass the signal?  Would there be a delay between the first and the last led? Any research on the web learned that the speed of this system is so fast, that you would be able to use it for a videowall. (You can let your fish watch "Finding Nemo" from your light hood, as you like) This LED's are also used for DIY Ambilight systems and effect lightning for disco's, so there seems to be no problem at all.

The main advantage seems the lack of a central LED driver. On the other hand, these LED's are more expensive. For my tank with 300 LED's, the costs for the driver and the LED's are:



System with driver 

and 5050 LED's

System with  

2812 LED's

300 LED's $  9.70 $ 26.40
Driver $ 18.00  -
Sum $ 27.70 $ 26.40



As you can see, for tanks like mine there is no real difference at all. For smaller tanks, the 2812 system would be even cheaper! Bigger tanks won't make more benefit, as the driver I've used was able to control 30 Watt of LED's, which means that 600 LED's need a second driver.

Another advantage -when you use strips of 5V- is the less complex power supply. The first system uses 12V strips (as the driver also uses 12V), the second system uses 5V strips, so all can be plugged in to the power supply without any restrictions.

The program on the Arduino can handle both scenario's, but when you want to use something else to drive the LED's make sure you know how to let your Arduino communicate with the driver.


My setup

This version of the daylight sim uses the next parts:

  • Three meters of RGB LED strip with the 2812 protocol (5 V)
  • One OLED screen (I2C 12864, 0.96 inch)
  • A push button

I use an Arduino Mega, but it will work with other ones or even clones. There is only one restriction: your board needs to have an I2C bus (on the Mega pin 20/21) to use the OLED.

The wiring is shown below, but only the I2C is critical.




connect oled arduino

connect pushbutton arduino







The LED strips get power from both sides of the strip, and the data line is wired like a snake. All LED's behind each other, no serial connections. (important!) The pushbutton needs a pulldown resistor to the ground, I use a 10K resistor, which works fine.

As I wanted to hide al Tec stuff, I made a remote with only the pushbutton and the OLED in a small case with 50 cm of cable. I have used an old PC cable from some device with 6 wires in it. So, the button and the OLED (7 wires together) share their +5 V. That seems to work. In the past, I had troubles with an LCD-screen and a shared ground. For me that's the reason to try to avoid sharing grounds.






Calibrating the LED strip

When you buy a strip of white LED's, there may/ be some specification about its color on the package. Cold light, warm white or something like 6600K. On RGB LED's of course there won't be such a description, but that does not mean that all strips are equal. Due to bad quality, it is possible to get different colors on one strip, even when that's not your intention. There is a difference in power consumption between red, green and blue LED's, and I noticed a slightly different / warmer color to the end of the strip due to underpowered blue LED's. Working with regular RGB strips, you have one common line (anode or cathode) which contains the total amount of energy for all LED's. And most of the time it's just a PCB line. As you may cut the strips to fit in your light hood, you may consider using a better conductor parallel to your strip.

And for the 2812 strips, it's even worse. Both power lines (+ and ground) are equal for all LED's, so I'll advice to make a central + and ground point in your light hood, and connect all parts of strip separate. The data line cannot be passed by, as it is also responsible for the addresses of the LED's. There must be one long line from the first LED to the last one, without any serial connections in it. As this line is digital with a very low power, I have not recognized problems with that line for being too long.

When you have a little problem to get all your RGB LED's exactly the same color, I'll suggest to do the calibration with the final light hood, to correct the warmth or cold of the light and set the average color to your desired value. And off course it's also possible this way to correct deviations in color because something in the light hood is reflecting your light with a slightly different color. The only problem can be that this calibration program uses the serial line of the Arduino for feedback and input, so during calibration there must be a device with an Arduino EDI be connected to it.

By the way, this kind of calibration is necessary to let the Arduino convert Kelvin colors to RGB-values needed for the LED's. If you want to use the program by only entering RGB codes (which is also possible, because colors like "blue moonlight" cannot be expressed in Kelvin), calibrating is not necessary. The final program only uses the calibration data when translating Kelvin.

The calibration program:


//LED calibration 
#include <Adafruit_NeoPixel.h>                                                         //<-- 2812
#define PIN 6                                                                          //<-- 2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(300, PIN, NEO_GRB + NEO_KHZ800);           //<-- 2812

int pixels = 300;
int red    = 200;
int green  = 200;
int blue   = 200;

void setup() {
  strip.begin();                                                                  //<-- 2812;                                                                   //<-- 2812

  Serial.println ("RGB LED calibration");
  Serial.println ("To change a color, send it with your serial monitor.");
  Serial.println ("For example, R181 changes the intensity of red to 181 (values between 0 - 255)");

void loop() {
  for (int i = 0; i <= pixels; i++){
    strip.setPixelColor(i,strip.Color(red, green, blue));                         //<-- 2812
  };                                                                   //<-- 2812
  Serial.println ("The current color is:");
  Serial.println ("Red: " + String(red) );
  Serial.println ("Green: " + String(green));
  Serial.println ("Blue: " + String(blue));   
  boolean waitForInput = true;

  while (waitForInput) {
    if (Serial.available()){
      waitForInput = false;

  char c =;
  int h = - 48;
  int t = - 48;
  int e = - 48;;; //Takes the last 2 characters (\r\n) of the input out the buffer 

  if (c == 'R' || c == 'r'){
    red = (h * 100) + (t * 10) + e;
} if (c== 'G' || c == 'g'){ green = (h * 100) + (t * 10) + e; } if (c == 'B' || c == 'b'){ blue = (h * 100) + (t * 10) + e; } }


Dwnldicon Download the Daylight simulator


All lines above marked with a //<--2812, are especially meant for the usage with the Adafruit Neopixel library. (It has to be installed!). If you use another way of controlling your LED's, skip that rules and replace them with code for your situation.

When the program runs, it uses the serial line to communicate. It tells you the current color, and you can pass information using the serial line to your Arduino, to change the color. All commands exist of 4 characters: you start with an R, G or B to tell which color you want to change, with thereafter a value of 3 digits! (use leading zero's! the value of 7 is typed as 007). After sending the command, you'll see the color of the light change immediately, and on your serial monitor the new values of R, G and B are shown.

Just enter values until you are satisfied with the neutral color of white, but also with the brightness. Depending on your LED's, it is possible that your amount of light is too bright. For my situation and LED's, I came to a neutral color of white with the next setting:

  • Red: 255
  • Green: 181
  • Blue: 90


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:

 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:


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


display.begin(SSD1306_SWITCHCAPVCC, 0x3C);




Dwnldicon Download the Daylight simulator



Powered by 2014 - All Rights Reserved.