207 lines
4.8 KiB
JavaScript
207 lines
4.8 KiB
JavaScript
const {
|
|
HCColorLamp,
|
|
StateUpdateManager
|
|
} = require('homecontrol-control-base');
|
|
|
|
const {
|
|
MilightController,
|
|
commands2,
|
|
} = require('node-milight-promise');
|
|
|
|
const mergeOptions = require('merge-options');
|
|
|
|
class HCmilight extends HCColorLamp {
|
|
constructor(config) {
|
|
super(config);
|
|
|
|
if (!("address" in this._configuration)) {
|
|
throw new Error(`Required configuration field "address" is missing"`);
|
|
}
|
|
|
|
this._zone = (this._configuration.zone !== undefined) ? this._configuration.zone : 1;
|
|
|
|
let opts = {
|
|
ip: this._configuration.address
|
|
};
|
|
|
|
opts = mergeOptions(opts, {
|
|
commandRepeat: 2,
|
|
}, this._configuration.controllerOpts);
|
|
|
|
this._state.brightness = 100;
|
|
this._state.color.l = 100;
|
|
this._state.color.sat = 0;
|
|
|
|
this._light = new MilightController(opts);
|
|
|
|
this._sumanager = new StateUpdateManager(this._state);
|
|
}
|
|
|
|
// overwrite to make use of the SUManager
|
|
get state() {
|
|
return this._sumanager.state.clone();
|
|
}
|
|
|
|
get effects() {
|
|
return [
|
|
{name: "Disco Mode", id: "disco"}
|
|
];
|
|
}
|
|
|
|
turnOn() {
|
|
let futureState = this.state;
|
|
futureState.on = true;
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
|
|
this._light.sendCommands(commands2.rgbw.on(this._zone));
|
|
|
|
return this._light.close().then(() => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
turnOff() {
|
|
let futureState = this.state;
|
|
futureState.on = false;
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
|
|
this._light.sendCommands(commands2.rgbw.off(this._zone));
|
|
|
|
return this._light.close().then(() => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
setBrightness(brightness) {
|
|
let futureState = this.state;
|
|
futureState.brightness = brightness;
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
|
|
this._light.sendCommands(
|
|
commands2.rgbw.on(this._zone),
|
|
commands2.rgbw.brightness(brightness)
|
|
);
|
|
|
|
return this._light.close().then(() => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
setColor(color) {
|
|
let futureState = this.state;
|
|
futureState.color = fillPartialHSL(color, futureState.color);
|
|
futureState.effect = 'none';
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
|
|
if (futureState.color.sat < 60) {
|
|
this._light.sendCommands(
|
|
commands2.rgbw.on(this._zone),
|
|
commands2.rgbw.whiteMode(this._zone)
|
|
);
|
|
} else {
|
|
let hue = Math.round(convertHue(futureState.color.hue) * (255/360));
|
|
this._light.sendCommands(
|
|
commands2.rgbw.on(this._zone),
|
|
commands2.rgbw.hue(hue)
|
|
);
|
|
}
|
|
|
|
return this._light.close().then(() => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
setEffect(id) {
|
|
let futureState = this.state;
|
|
|
|
if (id == 'none') {
|
|
if (futureState.color.sat < 60) {
|
|
this._light.sendCommands(
|
|
commands2.rgbw.on(this._zone),
|
|
commands2.rgbw.whiteMode(this._zone)
|
|
);
|
|
} else {
|
|
let hue = Math.round(convertHue(futureState.color.hue) * (255/360));
|
|
this._light.sendCommands(
|
|
commands2.rgbw.on(this._zone),
|
|
commands2.rgbw.hue(hue)
|
|
);
|
|
}
|
|
|
|
futureState.effect = "none";
|
|
} else if (id == 'disco') {
|
|
this._light.sendCommands(
|
|
commands2.rgbw.on(this._zone),
|
|
commands2.rgbw.effectModeNext()
|
|
);
|
|
|
|
futureState.effect = 'disco';
|
|
} else {
|
|
return Promise.reject(new Error("Invalid effect id"));
|
|
}
|
|
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
return this._light.close().then(() => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = HCmilight;
|
|
|
|
//the milight hue values are fucking stupid
|
|
function convertHue(hue) {
|
|
if(hue < 240) {
|
|
return 240 - hue;
|
|
} else {
|
|
return 600 - hue;
|
|
}
|
|
}
|
|
|
|
function fillPartialHSL(newcolor, oldcolor) {
|
|
if(newcolor.sat != undefined && newcolor.l == undefined) {
|
|
newcolor.l = (newcolor.sat > 50) ? 50 : 100 - newcolor.sat;
|
|
}
|
|
|
|
//console.log(newcolor, oldcolor);
|
|
let color = {};
|
|
color.hue = (newcolor.hue != null) ? newcolor.hue : oldcolor.hue;
|
|
color.sat = (newcolor.sat != null) ? newcolor.sat : oldcolor.sat;
|
|
color.l = (newcolor.l != null) ? newcolor.l : oldcolor.l;
|
|
return color;
|
|
} |