Touchscreen RGB Light controller

Note: This project is now out of date, so it may not work on later versions of the Espruino firmware.

For our wedding we really wanted some lighting that could change colour in a slow, controlled way. It also needed to change between predefined colours that fitted with our colour scheme. We couldn't find a cheap way of doing this, so we decided to make something! This is the result!

 

 

 

You'll need:

 

Then connect:

 

The Code:

There's more information on controlling and wiring up the lights on the WS2811 page. The actual code you need to copy and paste in is:

var col = {r:127,g:127,b:127}; // currently selected colour
var touchDown = false; // is a finger on the touchscreen?
var cols = [{"r":228,"g":228,"b":11},{"r":170,"g":226,"b":30},{"r":223,"g":97,"b":30},{"r":245,"g":203,"b":119}]; // current colour palette
var colFrom = {"r":228,"g":228,"b":11}; // colour used in animation
var colTo = {"r":170,"g":226,"b":30}; // colour used in animation
var pos = 0.28; // where in the animation are we - from 0 to 1
 
var rgb = new Uint8Array(50*3); // colours that are used for the animation
 
var onInit = function () {
  clearInterval();
  require("Touchscreen").connect(touchCallback);
  SPI2.setup({baud:3200000,mosi:B15});
  SPI2.send4bit([255,0,0], 0b0001, 0b0011); // test
  LCD.clear();
  drawCols();
  drawRGB();
  setInterval(step, 50); // call 20 times a second
};
 
// Send the data to the LEDs
function updateLEDs() {
  SPI2.send4bit(rgb, 0b0001, 0b0011);
}
 
// Display a solid colour
function setSolidCol(c) {
  var cols = new Uint8Array([c.r,c.g,c.b]);
  for (var i=0;i<rgb.length;i+=3) 
    rgb.set(cols, i);
  updateLEDs();
}
 
// Display the nice blended colours
function setBlendedCol() {
  for (var i=0;i<50;i++) {
    var a = E.clip((i/25.0)+(pos*3)-2, 0, 1);
    rgb[i*3] = colFrom.r*(1-a) + colTo.r*a;
    rgb[i*3+1] = colFrom.g*(1-a) + colTo.g*a;
    rgb[i*3+2] = colFrom.b*(1-a) + colTo.b*a;
  }
  updateLEDs();
}
 
// When a touch occurs, this is called
function touchCallback(x,y) {
  touchDown = x!==undefined;
  var b = (y*1.2/LCD.getHeight() - 0.1)*256;
  if (b<0) b=0;
  if (b>255) b=255;
  // check for colour sliders
  if (x>280) { col.b = b; setSolidCol(col); drawRGB(); }
  else if (x>240) { col.g = b; setSolidCol(col); drawRGB(); }
  else if (x>200) { col.r = b; setSolidCol(col); drawRGB(); }
  else { // check for taps on the colour boxes
    for (var i=0;i<cols.length;i++) {
      var r = getColRect(i);
      if (x>r[0] && y>r[1] && x<r[2] && y<r[3]) {
        cols[i] = col.clone();
        drawCols();
      }
    }
  }  
}
 
// Draw the RGB sliders
function drawRGB() {
  for (var i=0;i<240;i+=16) {
    LCD.setColor(i*1.0/LCD.getHeight(),0,0);
    LCD.fillRect(200,i,239,i+15);
    LCD.setColor(0,i*1.0/LCD.getHeight(),0);
    LCD.fillRect(240,i,279,i+15);
    LCD.setColor(0,0,i*1.0/LCD.getHeight());
    LCD.fillRect(280,i,319,i+15);
  }
  var cr = col.r*LCD.getHeight()/256;
  var cg = col.g*LCD.getHeight()/256;
  var cb = col.b*LCD.getHeight()/256;
  LCD.setColor(1,1,1);
  LCD.fillRect(200,cr-8,239,cr+8);
  LCD.fillRect(240,cg-8,279,cg+8);
  LCD.fillRect(280,cb-8,319,cb+8);
}
 
// Get the rectangle of a colour box
function getColRect(i) {
  var x = (i/4)|0;
  var y = i - (x*4);
  return [x*60,y*60,(x+1)*60,(y+1)*60];
}
 
// Draw the colour boxes
function drawCols() {
  var s = 60;
  for (var i=0;i<cols.length;i++) {
    var c = cols[i];
    var r = getColRect(i);
    LCD.setColor(c.r/255.0,c.g/255.0,c.b/255.0);
    LCD.fillRect(r[0],r[1],r[2],r[3]);
  }
}
 
 
function step() {
  if (touchDown) return; // touch down, so don't set
  // smoothly move between colours
  pos += 0.02;
  if (pos>1) {
    pos = 0;
    colFrom = colTo;
    colTo = cols[(Math.random()*cols.length)|0];
  }
  // send data to the LEDs
  setBlendedCol();
}
 
onInit();