Posts Tagged hue

Posted on Programming

Gently flickering flame, part 3

Now that we can talk to the lights, and choose colours, it’s time to make the lights flicker!

Hue doesn’t like you to send more than 10 commands per second. Since I have two lights I’m going to update them once every 200 milliseconds (5 times per second).

This is easy to do, using a normal game-type timing loop. In the constructor of your Main.hx, add addEventListener(Event.ENTER_FRAME, onFrame);.

Then create the onFrame function. Here’s mine:

private function onFrame(e:Event) {
	var n = Lib.getTimer();
	if ( n - _last >= 200 ) { // Don't send an update unless 200ms have elapsed
		if ( change ) { // I watch for colour and brightness changes, and set a this variable when they occur
			var data = {
				"bri": Math.round(Math.min( 254, cp.l*255 )), // brightness is between 0 and 254
				"hue": Math.round(Math.min(65535, cp.h*65535)), // hue is between 0 and 65535
				"sat":Math.round(Math.min( 254, cp.s*255 )) // saturation is between 0 and 254
			}
			var ds = Json.stringify(data);
			for (n in Reflect.fields(lights)) { // Loop through all the lights. We want the light keys, hence the reflection
				hue.update(n, 'state', ds); // Update the light
			}
			change = false;
		} else if (cp.flicker) { // This is the flickering part! cp is my colour picker/user interface's name
			var hsl = flicker.flick( cp.h, cp.s, cp.l );  // The magic flicker function!
			var data = {
				"bri": hsl[2],
				"hue": hsl[0],
				"sat": hsl[1],
				"transitiontime": 2
			}
			var ds = Json.stringify(data);
			for (n in Reflect.fields(lights)) {
				hue.update(n, 'state', ds); // Update the light
			}
		}
		_last = n;
	}
}

For the flicker itself, I kept it pretty simple. I might eventually try a normally distributed pseudo-random variance on the hue.

class Flicker {
	public function new() {}
	public function flick(h:Float, s:Float, l:Float) {
		var b = clamp(0, vary(l*254, 0.2), 254); // Vary brightness by 20%
		var h = clamp(0, vary(h*65535, 0.05), 65535); // Vary hue by 5%
		var s = clamp(0, h*254, 254);
		return [h, s, b];
	}
	function vary(orig:Float, variance:Float):Int {
		var max = orig * variance;
		var half = max/2;
		return Math.round(orig + Math.random()*max - half);
	}
	function clamp( min, val, max ) {
		return Math.round( Math.max( min, Math.min( max, val ) ) );
	}
}
Posted on Programming

Gently flickering flame, part 2 (colours)

Now the we can talk to the lights, It’s time to deal with colours. We can’t just send RGB to the API, so I made a class that displays a rectangle of colours, and can convert from HSL to RGB for displaying each one. The HslToRgb function I stole from stackoverflow.

package;

import openfl.display.Sprite;
import openfl.events.MouseEvent;
import openfl.events.Event;


class Colours extends Sprite {
	private var _width:Int = 60; // Number of hues
	private var _height:Int = 30; // Number of saturations
	private var size:Int = 10;
	
	public var h:Float;
	public var s:Float;
	
	
	public function new() {
		super();
		var l = .9;
		for(x in 0..._width) {
			for(y in 0..._height) {
				var h = _height/2;
				var lo = (1-(y/_height/2)); // This is so it fades into white rather than grey
			
				var rgb = hslToRgb( x*1.00/_width, y*1.00/_height, lo);
				var c = rgb[0];
				c = (c<<8) + rgb[1];
				c = (c<<8) + rgb[2];
				graphics.beginFill(c);
				graphics.drawRect(x*size,y*size,size, size);
				graphics.endFill();
			}
		}
		addEventListener(MouseEvent.CLICK, onclick);
		addEventListener(MouseEvent.MOUSE_MOVE, onmove); // So it picks up finger drags
	}
	
	private function onmove(e:MouseEvent) {	
		if ( !e.buttonDown ) return;
		onclick(e);
	}
	private function onclick(e:MouseEvent) {
		h = Math.min(1, e.localX/size/_width);
		s = Math.min(1, e.localY/size/_height);
		var l = 0.5; // This is alpha
		var rgb = hslToRgb(h,s,l); 
		dispatchEvent( new Event(Event.CHANGE) );
	}
	
	/**
	* Converts an HSL color value to RGB. Conversion formula
	* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
	* Assumes h, s, and l are contained in the set [0, 1] and
	* returns r, g, and b in the set [0, 255].
	*
	* @param   Number  h       The hue
	* @param   Number  s       The saturation
	* @param   Number  l       The lightness
	* @return  Array           The RGB representation
	*/
	public function hslToRgb(h:Float, s:Float, l:Float):Array{
		var r:Float, g:Float, b:Float;
	
		if(s == 0){
			r = g = b = l; // achromatic
		}else{
			var hue2rgb = function hue2rgb(p:Float, q:Float, t:Float):Float{
				if(t < 0) t += 1;
				if(t > 1) t -= 1;
				if(t < 1/6) return (p + (q - p) * 6 * t);
				if(t < 1/2) return (q);
				if(t < 2/3) return (p + (q - p) * (2/3 - t) * 6);
				return (p);
			}
	
			var q:Float = l < 0.5 ? l * (1 + s) : l + s - l * s;
			var p:Float = 2 * l - q;
			r = hue2rgb(p, q, h + 1/3);
			g = hue2rgb(p, q, h);
			b = hue2rgb(p, q, h - 1/3);
		}
	
		return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
	}
}