Skip to content

Commit

Permalink
feat: add white balance support (#30)
Browse files Browse the repository at this point in the history
This currently uses channels 4-5 for temperature and brightness respectively. RGB values must be 0 for temperature and brightness to take effect.

Channel 4-5 control temperature/brightness when RGB values are 0. RGB overrides brightness (channel 5).
  • Loading branch information
TeakKey7 authored and sinedied committed Jun 28, 2023
1 parent e1dd3ab commit fc71e98
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 13 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ Hue light can automatically perform transitions from one state to another in a s
useful since there is a somewhat low update rate limitation on Hue lights (see next section for more details). If you
want to go creative and be able to adjust transition times dynamically, you can dedicate a DMX channel for it.

#### White control

Channel 4-5 for each fixture are reserved for white control. When R/G/B channels are at value '0', channel 4 will control temperature, and channel 5 will control brightness. Brightness is currently overriden by R/G/B channels.
## Philips Hue response times vs DMX

With the Philips Hue API it’s only possible to update the state of bulbs 10 times per second, 1 bulb at a time.
Expand Down
16 changes: 8 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ class DmxHue {
options.lights = ordered.concat(remaining);
options.transitionChannel = options.transition === 'channel';
options.colors = {};
const dmxChannelCount = (3 * options.lights.length) + (options.transitionChannel ? 1 : 0);
const dmxChannelCount = (5 * options.lights.length) + (options.transitionChannel ? 1 : 0);
const extraDmxAddress = options.address + dmxChannelCount - 512;

if (extraDmxAddress >= 0) {
console.warn(chalk.yellow('Warning: not enough DMX channels, some lights will be unavailable'));
const lightsToRemove = Math.ceil(extraDmxAddress / 3.0);
const lightsToRemove = Math.ceil(extraDmxAddress / 5.0);
options.lights = options.lights.slice(0, -lightsToRemove);
}

Expand All @@ -105,7 +105,7 @@ class DmxHue {
}
options.lights.forEach(light => {
console.log(` ${chalk.cyan(`${currentAddress}:`)} ${light.name} ${chalk.grey(`(Hue ID: ${light.id})`)}`);
currentAddress += 3;
currentAddress += 5;
});
console.log('\nArtNet node started (CTRL+C to quit)');
});
Expand All @@ -128,7 +128,7 @@ class DmxHue {
address++;
}

const dmx = dmxData.slice(address, address + (3 * options.lights.length));
const dmx = dmxData.slice(address, address + (5 * options.lights.length));
let j = 0;
const length = options.lights.length;
let indices = Array.from({length}, (_, i) => i);
Expand All @@ -137,16 +137,16 @@ class DmxHue {
let i;
for (i of indices) {
const lightId = options.lights[i].id;
j = i * 3;
const color = dmx.slice(j, j + 3);
j = i * 5;
const color = dmx.slice(j, j + 5);
const previous = options.colors[lightId];

// Update light only if color changed
if (!previous || color[0] !== previous[0] || color[1] !== previous[1] || color[2] !== previous[2]) {
if (!previous || color[0] !== previous[0] || color[1] !== previous[1] || color[2] !== previous[2] || color[3] !== previous[3] || color[4] !== previous[4]) {
// Rate limit Hue API to 0,1s between calls
const now = new Date().getTime();
if (options.noLimit || now - this._lastUpdate >= 100) {
const state = this._hue.createLightState(color[0], color[1], color[2], options);
const state = this._hue.createLightState(color[0], color[1], color[2], color[3], color[4], options);
this._lastUpdate = now;
this._hue.setLight(lightId, state);
options.colors[lightId] = color;
Expand Down
20 changes: 15 additions & 5 deletions lib/hue.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,21 @@ class Hue {
.then(result => result.lights, () => Util.exit('No lights found'));
}

createLightState(r, g, b, options) {
const state = hue.lightState.create().transition(options.transition);
if (r === g && g === b && b === 0) {
createLightState(r, g, b, tmp, br, options) {
const state = hue.lightState.create().transition(options.transition);
function map_range(value, low1, high1, low2, high2) {
return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
}
var temp = map_range(tmp, 0, 255, 153, 500);
var bri = map_range(br, 0, 255, 0, 100);
if (r === g && g === b && b === bri && bri === 0) {
state.off();
} else if (options.colorloop && r === g && g === b && b === 1) {
} else if (r === g && g === b && b === 0) {
state
.on()
.white(temp, bri)
}
else if (options.colorloop && r === g && g === b && b === 1) {
state
.on()
.effect('colorloop')
Expand All @@ -28,7 +38,7 @@ class Hue {
const hsv = Color.rgb(r, g, b).hsv().array();
state.on()
.effect('none')
.hsb(hsv[0], hsv[1], hsv[2]);
.hsb(hsv[0], hsv[1], hsv[2]);
}
return state;
}
Expand Down

0 comments on commit fc71e98

Please sign in to comment.