Creating an Ambilight mood light for your television
In the struggle to find more cool things to do with the arduino, I thought I’d do what someone on twitter had done, make an “Ambilight”, an ambient light behind your TV that colours whatever is behind your TV the same colour as the average colour on your screen – pretty cool! Some Philips TV have this, but I’m not willing to spend extra on that (and I have a TV). I read Szymon Kobalczyk’s Blog and thought I’d give it a whirl. Currently I’m using one of my existing BlinkMs, but I’ve ordered two RGB LED strips and the necessary (hopefully) components from farnell.
The core idea is:
- Run “Boblightd”, which monitors the screen (excuse the pun) and calculates the average colour, passing it to a program that sends the message via serial to…
- An arduino listening for colours, and changes the colour of the BlinkM/RGB LED strip accordingly
This is the result of mine on my computer monitor, looks much better in real life (skip to 30-40s for best demo). Will be even better when the RGB LED strip arrives – that’ll be going behind my 42″ TV downstairs.
Installing Boblightd on Ubuntu Karmic
Installing Boblightd wasn’t quite so straightforward as I’d hoped as it requires a whole bunch of dependencies, and on my two machines, it needed a different bunch (despite both being the most up to date Ubuntu Karmic). For some reason, the boblightd webserver is blocking my IP address (not a static IP address) but fortunately, downloads still work – I’m using version 1.3
First, the dependencies:
sudo apt-get install libx11-dev libxpm-dev x11proto-xext-dev libxext-dev libx11-dev libxrender-dev libavcodec-dev libavformat-dev libswscale-dev libavdevice-dev libportaudio-dev mesa-common-dev
Then, run ./configure, make and sudo make install
Grab my config file and change the script location to wherever you will be putting the following script.
The Perl Script
Boblightd runs a specified program, and prints three floats to stdin, space separated, and then a new line, and repeats. This perl script is one loop that gets the standard in, splits it on the space, converts the floats to ints, and then to hex, and then writes it to the serial port (after checking it is different from the last one, just to save arduino processing time). Change ttyUSB1 to wherever your arduino is.
#!/usr/bin/perl -w use Device::SerialPort qw(ARAM :STAT 0.07 ); use Time::localtime; my $PORT = "/dev/ttyUSB1"; my $ob = Device::SerialPort->new($PORT); $ob->baudrate(115200); $ob->write_settings; open(SERIAL, "+<$PORT"); $lastOutput = ""; while (1) { $in = <STDIN>; @rgb = split(/ /, $in); $r = int($rgb[0] * 255); $g = int($rgb[1] * 255); $b = int($rgb[2] * 255); $rHex = sprintf("%02X", $r); $gHex = sprintf("%02X", $g); $bHex = sprintf("%02X", $b); $output = "$rHex$gHex$bHex\n"; if ($lastOutput ne $output) { print SERIAL $output; print $output; $lastOutput = $output; } }
If you haven’t already got Device::SerialPort, run these (as root):
perl -MCPAN -e shell
install Device::SerialPort
The Arduino Code
The Arduino code is very simple, hacked from the BlinkM Tester example. Remember to Sketch > Add File and include the BlinkM_funcs.h file before trying to run this. Change blinkm_addr to the address of your BlinkM (probably 0×09).
#include "Wire.h"
#include "BlinkM_funcs.h"
#define BLINKM_ARDUINO_POWERED 0
byte blinkm_addr = 0x01;
#include
char serInStr[30];
void setup()
{
BlinkM_begin();
delay(100);
Serial.begin(115200);
BlinkM_stopScript( blinkm_addr );
BlinkM_setRGB( blinkm_addr, 0,0,0);
}
void loop()
{
if( readSerialString() ) {
byte r = toHex( serInStr[0],serInStr[1] );
byte g = toHex( serInStr[2],serInStr[3] );
byte b = toHex( serInStr[4],serInStr[5] );
BlinkM_setRGB( blinkm_addr, r,g,b);
}
}
#include
uint8_t toHex(char hi, char lo)
{
uint8_t b;
hi = toupper(hi);
if( isxdigit(hi) ) {
if( hi > '9' ) hi -= 7;
hi -= 0x30;
b = hi<<4;
lo = toupper(lo);
if( isxdigit(lo) ) {
if( lo > '9' ) lo -= 7;
lo -= 0x30;
b = b + lo;
return b;
}
}
return 0;
}
uint8_t readSerialString()
{
if(!Serial.available()) {
return 0;
}
delay(5);
int i = 0;
while (Serial.available()) {
serInStr[i] = Serial.read();
i++;
}
serInStr[i] = 0;
return i;
}
Putting it all together
Upload the arduino code.
Run boblightd -c popen.conf
Run boblight-X11
And now watch a movie, simple!