It’s a well-known fact that watching too much TV, especially in the dark, puts a strain on your eyes. There are many bias (or ambient lighting) systems out there for TVs and monitors, most of which rely on an HDMI input in order to capture the image before it is sent to the screen. Obviously, this is not much use with modern smart TVs that have a plethora of applications built in such as Netflix, Amazon Prime, BBC iPlayer, PLEX etc.
I started to hunt for an alternative solution and came across an excellent piece of software written by Waldo Bronchart, which he has written up here
This uses a Raspberry Pi, a USB camera and some WS2801 LEDs. The software captures the image from the USB camera, detects the colour at the edges of the picture and drives the LEDs to match. It even has a nice little companion app that allows you to draw a trapezoid around the region of the image the camera captures in order to accurately define the edges of the screen and adjust various camera settings (Gain, saturation, brightness, contrast etc). More on this later. for now, lets look at the parts list required: (All parts below are the actual ones I used, feel free to try different ones, but pay attention to the power requirements of the LEDs)
A power socket: adaptare Adapter DC Barrel Jack Socket Power Terminal Block (Pack of 1, 5.5 x 2.1 mm, 93522
A Power Supply: Tesfish 5V 8A LED Strip Power Supply Converter Adapter 5.5×2.1/2.5mm For WS2811/2801 LED String Light
Some Wire: 18 Gauge Electrical Wire , 18 AWG Silicone Wire Hook Up wire Cable [10 ft Black And 10 ft Red] Soft and Flexible 150 Strands 0.08mm of Tinned copper wire High temperature resistance
LED Strips: BTF-LIGHTING WS2801 5050 SMD RGB 32Leds/m 96leds Addressable Individual Waterproof IP67 Black PCB Pixel Strip Light DC5V 3M 9.8ft
USB Camera: Logitech C270 Webcam HD High-Quality Video and Audio Technology – Black
And of course, a Raspberry Pi (i used a model 3) minimum 8Gb SD Card, some tools – wire strippers, soldering iron, solder, volt meter etc.
I found a 3m roll of WS2801 LEDs is perfect for a 42″ screen – you may need more or less than I had, so measure up first!
Preparing the SD card
You’ll need at least 4GB free space on the card. I managed to make this fit on an 8Gb card by removing some of the software installed with the Pixels distro.
First of, head off to raspberrypi.org and download the Pixels image and write this to your card. Boot the Pi and be sure to enable SSH, and the SPI interface.
You can find my fork of all the code here
SSH to your PI, and run
Run it with
This will remove the wolfram engine and libreoffice in order to make some room (8gb card minimum required) and install all the pre-requisites, and compile all the required software. This is going to take a long time, just over 3 hours on a raspberry pi3!
once finished, look at HardwareConfig.h in the ~/AmbientLightServer directory to see how to set up your LEDs (you will need 2 strips).
After editing this file, you will need to re-compile just the AmbientLightSever application, these only take a minute or so. You must be in the AmbientLightServer directory, then use this command:
the -j4 tells the compiler to use all 4 cores. The other option you may wish to change is the starting LED position. you can find this in the TrapezoidSampler.cpp file at line 43. don’t forget to recompile if you change this setting!
That’s it for the Raspberry Pi software, next let’s move onto the hardware. For this project, we cut the LED strip in half to have two equal lengths. you should see the point at which they can be cut easily enough – there will be 2 sets of 4 solder pads annotated +v d1 c1 and gnd. Cut cleanly between the two rows.
The image on the right shows the power wiring – 2 short positive and ground wires to power the pi, and 4 longer wires, 2 live and 2 ground, to power the LED strips. be careful measuring the lengths, they will need to stretch from the Pi (which I mounted in the centre rear of the TV) to the top and bottom of the screen, or opposite corners, depending on if you changed the start position in TrapezoidSampler.cpp. At this point, I plugged the power supply in, connected it to the socket and checked the polarity! You will also need another 4 identical lengths of wire for the data connections.
Solder the power wires from the PSU connector you have made to the Pi, pins 2 (Live) and 6 (Ground). Solder the other 2 pairs of power to the LED strips, taking care to note the polarity, and make sure you solder to the beginning of the strip. (Mine had arrows showing the direction of flow)
Next is the data and clock wires. may attention to the LED strip – it should be marked C1 and D1 for clock and data respectively. If you see C0 and D0, chances are you are at the wrong end of the strip.
These need to be soldered to the PI – use these pins for one strip – Pins 11 (data) and 12 (clock) for the first strip, and pins 15 (data) and 16 (clock) for the second. You can find a handy reference here showing the pin numbers.
Now DOUBLE CHECK YOUR WIRING!! Make sure there are no shorts anywhere. Hook up the camera to a USB port and power and boot the Pi. with mine, some of the LEDs light up on boot up. Ignore it for now, we just want to check everything works
SSH into the Pi, cd to the AmbientLightServer directory and run
The software should startup, then start reporting how many FPS it is receiving from the Camera.
The LEDS should all be lit, and change colour as you move the camera around. If not all of the LEDs are lit, check your config in Hardware.h and make sure the number of LEDs etc are set correctly.
The next thing you are going to want to do, before mounting the LEDs, is to use the companion application to define the screen area in the captured image. For this, I used a windows 10 PC with Python and a copy of AmbientLightPyClient (https://github.com/waldobronchart/AmbientLightPyClient).
Install Python and check the options against those set below
Next install CX_freeze, with all the default options. The install PyQT4 with the defaults.
Download and extract the AmbientLightPyClient Open a cmd window in the directory and run build.bat
This will create a directory called build, and within that exe.win32-3.3 and in there you will find the Ambilight.exe
Make sure your raspberry pi is running the Ambient Light Server and launch the Ambilight.exe.
Go to the Server tab, and enter the IP address of your Pi and click connect
Use this to figure out the orientation of your LEDs before you attach them to the back of the screen!
You only need to run the client if you move the camera, or want to adjust the colours etc on the colour tab – AmbientLightServer saves the preferences locally on the Pi.
Now everything is working, go ahead and mount the LEDs and the Pi to the rear of the TV, and find a suitable location for your camera. (Hint, you can get clip-on wide angle lens adapters from eBay, allowing you to position the camera closer)
Having this working is great, but it’s a bit of a pain to have to SSH into your Pi to turn it on and off all the time, so I have a few more steps.,. I purchased a smart plug for the power supply and installed some additional Python modules on the Pi so I could write a simple script to turn off the LEDs when I had finished with them.
Let us install the required python and libraries:
sudo apt-get install git build-essential python-dev cd ~ git clone https://github.com/adafruit/Adafruit_Python_WS2801.git cd Adafruit_Python_WS2801 sudo python setup.py install
now lets create a script to turn the LEDs off:
cd ~/AmbientLightServer nano off.py
from __future__ import division import time # Import the WS2801 module. import Adafruit_WS2801 import Adafruit_GPIO.SPI as SPI # Configure the count of pixels: PIXEL_COUNT = 47 # The WS2801 library makes use of the BCM pin numbering scheme. See the README.md for details. # Specify a software SPI connection for Raspberry Pi on the following pins: PIXEL_CLOCK = 22 PIXEL_DOUT = 23 pixels = Adafruit_WS2801.WS2801Pixels(PIXEL_COUNT, clk=PIXEL_CLOCK, do=PIXEL_DOUT) # Alternatively specify a hardware SPI connection on /dev/spidev0.0: #SPI_PORT = 0 #SPI_DEVICE = 0 #pixels = Adafruit_WS2801.WS2801Pixels(PIXEL_COUNT, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE)) # Clear all the pixels to turn them off. pixels.clear() pixels.show() # Make sure to call show() after changing any pixels! PIXEL_CLOCK = 17 PIXEL_DOUT = 18 pixels = Adafruit_WS2801.WS2801Pixels(PIXEL_COUNT, clk=PIXEL_CLOCK, do=PIXEL_DOUT) pixels.clear() pixels.show() # Make sure to call show() after changing any pixels!
press CTRL+X then Y to save
This is how my worklows look under iOS:
Thats it. Please feel free to leave any questions or comments below.