FacebookTwitterGoogle+Share

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 ) ) );
	}
}

Comments