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