Bias lighting as radiator for Snap-CI

Bias lighting

Recently I got myself a RBG led strip with a remote control similar to this one for bias lighting on my computer, before I had just a regular lamp sitting behind my monitor. If you want to know more about bias lighting check this post on Coding Horror. Here's how it looks now:

RGB led strip for bias lighting

Turning the bias lighting into a build radiator

The fact that I could change the colors of the RGB strip with a remote control gave me the idea of making it a build radiator with Arduino. First step was to make the Arduino send the same IR (infrared) commands my remote sends. Fortunately all reverse engineering of this common remote was done already, the receiver expects IR commands using the NEC protocol.

Getting Arduino to send the IR commands

Arduino has a wonderful library to send IR commands. You just need to know which protocol (of the most common used) and which commands the IR receiver expects. Bellow the IR receiver attached to the RGB strip:

IR receiver

Truth is, it was not as simple as it sounds, at least for me. Getting Arduino to send the proper commands took me into a journey of discovery of IR protocols, timer interrupts and prescalers on micro controllers and finally striping down an old DVD remote control we had to get the IR led.

After being able to send IR commands to the RGB receiver, I settled with this Arduino code (on github):

#include <IRremote.h>

int BUITIN_LED = 13; // Arduino's builtin led

// IR remote commands for RBG led strip which are IR NEC format
// format: 0x00ff[command][command ^ 0xff]
// see: http://blog.allgaiershops.com/2012/05/10/reversing-an-rgb-led-remote/
// see: http://www.instructables.com/id/Reverse-Engineering-RGB-LED-Bulb-with-IR-remote/?ALLSTEPS
// see: http://www.sbprojects.com/knowledge/ir/nec.php
unsigned long IR_RED    = 0x00ff1ae5; // command for red color
unsigned long IR_GREEN  = 0x00ff9a65; // command for green color
unsigned long IR_YELLOW = 0x00ff2ad5; // command for yellow color

// IR send interface, uses pin 3 on Arduino
// see: http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html
IRsend irsend;

// hold the current state, arduino will keep issuing this
// command in a loop
unsigned long IR_CURRENT_STATE;

void setup() 
{
    Serial.begin(9600);
    pinMode(BUITIN_LED, OUTPUT);
    IR_CURRENT_STATE = IR_GREEN; // start green
}

void blinkBuiltInLed() {
    digitalWrite(BUITIN_LED, HIGH);
    delay(100);
    digitalWrite(BUITIN_LED, LOW);
}

unsigned long readCurrentState(char command) {
    switch (command) {
        case 'r':
            return IR_RED;
            break;
        case 'g':
            return IR_GREEN;
            break;
        case 'y':
            return IR_YELLOW;
            break;
        default:
            return IR_CURRENT_STATE;
    }
}

void sendIRCommand(unsigned long ircommand) {
    irsend.sendNEC(ircommand, 32);
    blinkBuiltInLed();
}

void loop()
{
    // read commands from serial 'r', 'g' or 'y'
    if(Serial.available() > 0) {
        char command[1];
        Serial.readBytesUntil('\n', command, 1);
        IR_CURRENT_STATE = readCurrentState(command[0]);
    }
    sendIRCommand(IR_CURRENT_STATE);
    delay(1000);
}

During the loop Arduino will read from the serial and if we write r,g or y it will issue the IR command for Red, Green and Yellow like the remote would do, but it will keep issuing it every second. Bellow is how each of the bias lighting colors looks like (Red, Yellow and Green):

red
radiator yellow
radiator green
radiator

Monitoring a build on Snap-CI

Snap-CI provides access to build status using a cctray formatted XML. The next step was to make a script that can fetch the cctray, parse it and write to the serial interface where the Arduino is attached to. Luckily again most of the heavy lifting is done already, using the 'cctray' and 'serialport' gems I just need to send the proper commands. Here's the Ruby script which fetches the cctray information and sends the build statuses back to Arduino (code on github).

#!/usr/bin/env ruby

require 'serialport'
require 'cctray'

class BuildRadiator
  # find which serial your Arduino is using and set it here.
  ARDUINO_SERIAL_PORT = '/dev/tty.usbmodem14631'

  STATUS_COMMAND = {
    'Building' => 'y',
    'Failure'  => 'r',
    'Success'  => 'g'
  }

  def initialize
    @serial = SerialPort.new(ARDUINO_SERIAL_PORT, 9600, 8, 1, SerialPort::NONE)
  end

  def send(command)
    @serial.write command
  end

  def notify(status)
    send STATUS_COMMAND[status]
  end

end

buildradiator = BuildRadiator.new
cctray        = CCTray.new("https://snap-ci.com/mavcunha/misc/cctray.xml")

while true do
  puts "Fetching build status"
  p = cctray.fetch.first

  status = p.activity == 'Building' ? p.activity : p.last_build_status

  puts "Notifying build radiator of status: #{status}"
  buildradiator.notify status

  sleep 10
end

This script will loop every 10 seconds, fetch the cctray information and notify my Arduino. The Arduino then reads the command and issues the proper IR command to the RGB strip.

Notes

  • One thing that I couldn't solve is that when SerialPort initializes it resets Arduino which in turn makes the light green until the next build status (if not green) is retrieved. I'm probably doing something wrong.
  • If you send anything into the serial port, the code will retrieve each byte and apply the readCurrentState routine, it will ignore invalid commands but could lead to a delay from Arduino part to issue the IR command.
  • I used embedXcode for this code, that's why you might see more files than a regular Arduino IDE project if you check the github project.
  • If a group of developers sharing a table have the same strip attached to the back of their monitors one Arduino could potentially issue IR commands to change all bias lighting and it could be anything from build monitor to production issues and so on. Sounds like something I would like to see.
Published in Apr 21, 2014