Original July 19, 2014

I recently decided to put an aquarium in my office as a bit of background noise and occasional distraction. In getting the equipment set up, I purchased a Current Satellite LED+ light. This is a freshwater-specific light aimed at providing good color for the types of plants most often used in freshwater systems. It also has a remote control that allows you to change color, and invoke certain dynamic modes (e.g. flashing colors to simulate a thunderstorm over a lake).

Except — they did not make the remote/light with a timer, and it is necessary to limit light on an aquarium carefully to control algae growth. Moreover, it is desirable to have multiple periods per day as opposed to one long period of light.

As I was spending time deepening my knowledge of Linux, I decided to experiment with a Raspberry PI system as a controller. I decided on the Pi instead of Arduino mostly to live more in Linux for a while, but also because I wanted the control to be headless and web based, and networking seems easier there.

As I have had a couple inquiries as to how to accomplish it, I am writing this note to lay out the details, and post some associated code.

First some caveats and disclaimers –

  1. Electrical engineering is a LONG time in my background, so take all the circuit design with suitable skepticism; I welcome feedback,
  2. I am an instant-gratification type when I start such projects, so I bought the parts from Radio Shack. They were il-documented (both poorly and also inconsistently). I do not recommend them, search for similar efforts (mostly Arduino) with more standardized parts which should work better,
  3. This is built with a receiver as well as a transmitter, but the receiver is not used by the software as published; instead it is available if you need to program a different remote to scan and capture the codes.  You can ignore that circuit portion for the receiver if you are only using an LED+ (all the 3v section on the right).
  4. This page is a second draft; I have lightly tested the instructions, on my second build for a second tank, so expect some gaps – I welcome feedback.

OK, here’s the build steps, parts first:

  • Raspberry PI model B (I bought the startup kit from Radioshack which had lots of parts and a nice breadboard)
  • Humble Pi add-on card to do the final solder assembly
  • Radioshack part 276-142 (emitter and detector — use the emitter only, or buy a better one)
  • Radioshack part 276-640 detector (this is needed only if you want to record your own signals from the physical remote, e.g. to repeat what I am posting, or to do a different type of light)
  • LED Mount 276-080 to attach emitter to case
  • Radioshack 270-1806 project enclosure — this is much too big, and has poor mount (I glued in a custom cut piece of plastic to screw the PI onto). My goal was a water-resistant black box, and all the PI cases tend to be very open.  On the second one I just used the included case in the startup kit.
  • An NPN transistor, I used a 2N3904 that came with the PI. You need one with a 100:1 gain or better and about 200ma or better current flow.
  • Resistors: 15 ohm, 270 ohm, 10k ohm (anything vaguely in these ranges is fine, you can do the math to compare when you see the schematic).
  • RJ45 ethernet cord, USB power cord, Wifi dongle optional (I used a Trendnet TEW-649UB, but am not very happy with it as it runs very hot and needs a restart every couple months).

Next to clarify the goal of the project – I wanted a box that had no interaction with the user, no keys or buttons, no display, no flashing lights (most similar projects go after built in controls, which complicates the build). The idea is it sits there and controls the aquarium light, and that is all.  When user interaction is needed, it is done via the web (as opposed to any hardware interface). Secondly, I wanted it designed so the user can easily change the schedule without programming.  Finally, I wanted it to not prevent the use of the regular remote control – so the IR receiver is unchanged, and provided it is left exposed to the handheld remote, it still works.

Aside: An important consideration for your own project is whether the device should have other activities. I had wanted to do a flow sensor to be able to track historic filter performance, so as to be more accurately able to tell when it is time to clean the media. The inexpensive flow sensors, however, constricted the flow too strongly. Cheap sensors for temperature and even PH are pretty boring. Sensors for ammonia, Nitrates or Nitrates are very expensive. So this ended up only doing LED+ control. However, the PI (vs Arduino) makes a terrific platform for analytical measurements (think GNUplot) if you can identify some.

Here is the final schematic.

Pi Remote Schematic

Pi Remote Schematic

This entire circuit goes on the Humble Pi card, except the LED itself which goes onto a wire so it can be mounted in the case itself. I mounted all components except the IR Detector facing down (toward the PI), with the jumper wires on top, and the IR Detector on top. I placed the IR Detector inside the case (i.e. it will not work without opening the case) because its only purpose is a one-time programming of the codes by pushing buttons on the LED+ physical remote.

The following shots show how I configured it. You can do better, this was my first PCB soldering in 30 years, it is a bit embarrassing to show online, but this note is incomplete without it.

Top of Humble Pi (opposite main board)

Top of Humble Pi (opposite main board)

Bottom of Humble Pi (toward main board)

Bottom of Humble Pi (toward main board)

IR LED Mount

IR LED Mount

Cutouts for wires (could use grommets)

Cutouts for wires (could use grommets)

Assembled Unit

Assembled Unit

In Place Behind Tank

In Place Behind Tank

Now for the interesting part – code to make it all work. Much of this may not be interesting to linux gurus, but then again, maybe some of them can tell me how to do this better! These are the steps I followed to configure the OS, etc.

Caution: This build makes NO provision for security. None. In my case it is internal to my network and I could care less if someone (allowed on that network) could access the remote control. You may want to change the system password (pi) and add security in the HTML code, configure iptables for firewall like features, etc.

Note: My first tank was wired to ethernet.  The second had to be wireless.  I’ve updated this as noted with optional wireless configuration. You must connect at first wired however, to do the configuration.

  1. Download Raspbian from the Raspberry Pi web site (http://www.raspberrypi.org/downloads/). I used the September 2014 version kernel 3.12, obviously get a current version.
  2. Because I’m on Windows and wanted to make my SD card there, I also downloaded WinDiskImager (http://sourceforge.net/projects/win32diskimager/files/latest/download ). Install, run (as admin). Point it to the Raspbian image (after unzipping it) and let it write to the SD card. Get coffee, takes a while. I used a 16G card but it’s mostly empty (I’m using only about 5G, and could clean that up a lot).
  3. Connect ethernet cable, then USB power (note I’m going for a completely no-keyboard, no-display configuration. You can of course use the more conventional approach of using those at first.
  4. Look on my local router to find the IP address assigned (you may have a router handing out IP addresses, or a server, or… if you don’t know about DHCP and IP addresses, maybe stop here.
  5. SSH to that address (I used PTTY, use your favorite terminal emulation). Note that some versions of Pi software does not enable SSH by default, but raspbian does (at least now in this version). Login with the username “pi” and password “raspberry” (lower case)
  6. type sudo raspi-config, and use the options to expand the file system. While you are in there, under the advanced option, change the name (if desired).  Then reboot.
  7. Install NTP (you need this for a real time clock — note, this project does not work without an internet connection for NTP as there is no clock in the Pi). sudo apt-get install ntpdate
  8. Configure time zone. sudo dpkg-reconfigure tzdata and do the obvious for your location.
  9. Update raspbian
    • sudo apt-get update
    • sudo apt-get upgrade
    • sudo apt-get dist-upgrade
  10. Update PI firmware (these likely will change by the time you read this)
    • sudo apt-get install git-core
    • sudo wget http://goo.gl/1BOfJ -O /usr/bin/rpi-update && sudo chmod +x /usr/bin/rpi-update (be sure to unwrap that if it did before pasting)
    • sudo rpi-update
  11. Reboot and make sure everything is still working. Note you might consider a DHCP reservation for the Pi so it always stays at the same address.
  12. Optionally for wifi:
    • I used a Trendnet TEW-649UB, you may need to change things otherwise
    • Edit /etc/network/interfaces and include this section (portion of this may be there or different, remote any items under wlan0 other than these, and do not mess with other iface entries)
    • allow-hotplug wlan0  
    • iface wlan0 inet dhcp
    • wpa-ssid <mynetwork>  
    • wpa-psk <hexadecimal_key>
  13. The hex key can be found from: wpa_passphrase SID password
  14. Reboot, remove ethernet cable as it boots, check router for IP, reserve IP if needed, be sure to flush dns and/or any other issues as the IP may be the same or (most likely) will change.
  15. Install lirc (a very nice IR remote control tool)
    • sudo apt-get install lirc
  16. Add these two items to /etc/modules
    • lirc_dev
    • lirc_rpi gpio_in_pin=23 gpio_out_pin=22
  17. Type: sudo service lirc restart 
  18. You can only do the following two tests after installing the software below
  19. To test the receive function (if you hooked up the receiver):
    • sudo /etc/init.d/lirc stop
    • sudo modprobe lirc_rpi
    • mode2 –d /dev/lirc0
    • Then use the remote and codes should rapidly appear on the screen.
  20. You can test send with irsend SEND_ONCE Power and the unit should turn off and on. The LED needs to be fairly close to the LED+ receiver.
  21. Configure the web server:
    • sudo apt-get install apache2 php5 libapache2-mod-php5
    • sudo service apache2 restart
    • Hit the IP address of the PI with a web browser and you should get a default page saying “it works”
  22. Enable “www-data” to operate as root, so the web application can do things like shutdown (note this is completely, totally insecure). Edit /etc/sudoers and add to the end www-data ALL=(ALL) NOPASSWD: ALL
  23. Add the following to /etc/crontab at the end, to cause the schedule job to run once a minute (this is done preferably to trying to schedule each schedule step dynamically). The line is
    • 0-59 * * * * www-data bash /usr/lib/cgi-bin/remotecronjob.sh
  24. Install the necessary code items as a tarball from here and:
    • Review its contents to ensure you know what it is installing where.
    • Move to the PI (you may need FTP installed, or your favorite transfer program); to do FTP:
      • sudo apt-get install vsftpd
      • Edit /etc/vsftpd.conf and change local_enable and write_enable to yes (uncomment), then sudo service vsftpd restart
    • Unpack to the indicated directories (sudo tar -xPv -f LEDPlus.tar, or do them individually)
  25. Probably need a reboot here to make sure everything is set up.
  26. Now if you hit the IP address with a browser you should see the remote control.
    Pi Remote Web Page

    Pi Remote Web Page

  27. The following steps will reduce the amount of physical (ie. to SD card) IO that occurs, lengthening its life. These are fairly standard Linux steps that can be found in numerous documentation sites.
    • Type in the following:
      sudo dphys-swapfile swapoff
      sudo dphys-swapfile uninstall may give error, can be ignored
      sudo update-rc.d dphys-swapfile remove
      
    • Edit the file /etc/default/tmpfs and change RAMTMP=yes
    • Edit the file /etc/fstab and add/change these lines:
      tmpfs /var/log tmpfs defaults,noatime,nosuid,mode=0755,size=100m 0 0
      add noatime to both mmcblk0p1 and p2

      Note: no log file will be retained between boots like this.

    • Note apache won’t run like this however, as it won’t create the directories for logging (and they can’t be pre-created between boots as the temp area is wiped). You need this (see this). Create file /etc/init.d/make-tmpfs-dirs with this:
      ### BEGIN INIT INFO
      # Provides: log directories (etc) needed when directories are on tmpfs
      # Required-Start:
      # Required-Stop:
      # Default-Start: 2 3 4 5
      # Default-Stop:
      # Short-Description: Create tmpfs dirs
      # Description: date / time / ip address
      ### END INIT INFO
      #!/bin/sh
      mkdir /var/cache/debconf 
      mkdir /var/log/apache2 
      chown root:adm /var/log/apache2 
      chmod 750 /var/log/apache2 
      mkdir /var/log/postgresql 
      chown root:postgres /var/log/postgresql 
      chmod 774 /var/log/postgresql 
      exit 0
    • Change the file protections and set it to run on boot:
      sudo chmod u+x /etc/init.d/make-tmpfs-dirs
      sudo update-rc.d make-tmpfs-dirs defaults
    • Reboot and test that it all seems to be working.

When you first see the page, there will be a default schedule with two photo periods, the first ending at 12:20 with a slow fade that completes about 12:30, and the second with a fate that turns bluish around 22:11, fades to darker blue through several reductions in green and red until blue goes out completely at 22:45.  You do not need anything nearly so complex, you could have just an on and off, or just a “full spectrum” and “rgbdDown100” which would be one photo period and full light with a quick fade at the end. To create new items right click; to delete an item click the “X”.   When you create one, it comes in at midnight (00:00), edit the time and tab to sort.  Note you can’t schedule the up/down (with no number), only the 20% and 100%’s..

Note that you can invoke the program in debug mode by appending ?debug=1 to the end of the URL that appears (it should end in /remote.php, so make it http://yourcomputernameoraddress/remote.php?debug=1. This will show call information which may be helpful if things are not working at first.

Now… let’s talk about the power button.  I recommend you do not use it (on the web remote, or your real one).  If it ever misses you could end up reversing your cycle (i.e. in a schedule).  The reason is that it is a toggle — it will go on if off, or off if on.  So if it misses once, everything reverses.  A better idea is leave the unit on all the time, and instead dim 100% for all (rgbw), which will be the same (almost) as off.  Then when you want it on, just choose a button (e.g. full spectrum).  Effectively this means the unit is always on, ready for any light code, including “down” to turn all the lights off.

Note as you set up a schedule, it is a good idea to test it without times, especially if it has complicated up/down sequences.  To do this just look at the schedule, and click the corresponding button in that order.  Watch the aquarium and see what happens.  Adjust as needed.

Now for some caveats:

  • The program is all hard coded, and not intended to be adapted to other remote controls, but if you are a programmer it might give you a starting point
  • When running multiple LED+ you may find that some do not respond to a particular command or in the same fashion. Because of this, the program has some redundancy built in, for example simple commands are sent twice.  In the file /usr/lib/cgi-bin/remoteconfigure.sh are a few parameters, notably DELAY.  This is the length of a pause between each transmission in sequences.  I found if you send too fast, commands are missed. The value in the file now is what I need to make a group of four work reasonably reliably.  With just one of them, I found it could be about 4 times a short.  Adjust as needed.  Similarly the PCT20 and PCT100 are how many repeated transmissions of up or down are needed to get approximately 20% or 100% of the full range, again you may find your LED+ needs more or less.  I recommend first setting DELAY pretty slow (say .5) then the number of repeats, then reduce the delay until it no longer accomplishes a full 100% reduction.
  • Be sure the cron job data at the top right is updating when the web page is displayed.
  • A “Shutdown” button is on the web page since it’s a pain to SSH into the machine to shutdown. Use this when you can before powering off the device, the SSD will remain uncorrupt longer.
  • Note that because the cron job’s data is updated in /tmp which is cleared each boot, it takes a couple loops before the data is valid, after a reboot.
  • Please report bugs and suggestions.

Here is a photo of the second Pi I did for another aquarium.  This one has a remote IR emitter and uses WiFi, it’s also out of the area where it can get wet, so I used a more conventional case with it.

Pi Remote under Large Aquarium Stand (WiFi)

Pi Remote under Large Aquarium Stand (WiFi)

UPDATE INFO

  • 2/21/2015 – New version of the software posted which fixes some bugs (display of time omitted leading zeros, more conservative delays in transmission for reliability, some code cleanup and better error reporting).
  • 06/16/2016 – This whole web site was migrated, and this document needed heavy editing due to some idiotic Sharepoint issues (thanks Microsoft!); I hope I got all the typos out. The program files are unchanged.