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:
- A HY Mini-STM32 VCT6 3.2" board - see the Other Boards page. There are different boards and most should work - however they all have different pin connections
- A WS2811 LED string
- USB phone charger
Then connect:
- The white+red wires of the WS2811s to 0v and 5v
- The (input) green wire of the WS2811s to pin PB15. There are usually 2 green wires and the input is the female connector. Note that PB15 is a bit hard to see - it's on the top-right of the board, opposite the mislabelled pin PD14 (actually PB14)
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();