255 lines
6.9 KiB
JavaScript
255 lines
6.9 KiB
JavaScript
const {
|
|
HCColorLamp,
|
|
StateUpdateManager,
|
|
utils,
|
|
} = require('homecontrol-control-base');
|
|
|
|
const { Control } = require('magic-home');
|
|
|
|
class HCMagicHome extends HCColorLamp {
|
|
constructor(config) {
|
|
super(config);
|
|
|
|
if (!("address" in this._configuration)) {
|
|
throw new Error(`Required configuration field "address" is missing"`);
|
|
}
|
|
|
|
let opts = {
|
|
ack: (this._configuration.ack !== undefined) ? Control.ackMask(this._configuration.ack) : Control.ackMask(0x0F),
|
|
log_all_received: (this._configuration.logall !== undefined) ? this._configuration.logall : false,
|
|
connect_timeout: (this._configuration.connect_timeout !== undefined) ? this._configuration.connect_timeout : 10000,
|
|
command_timeout: (this._configuration.command_timeout !== undefined) ? this._configuration.command_timeout : 5000,
|
|
};
|
|
|
|
this._control = new Control(this._configuration.address, opts);
|
|
|
|
this._sumanager = new StateUpdateManager(this._state);
|
|
}
|
|
|
|
static get version() {
|
|
return require("./package.json").version;
|
|
}
|
|
|
|
// overwrite to make use of the SUManager
|
|
get state() {
|
|
return this._sumanager.state.clone();
|
|
}
|
|
|
|
get effects() {
|
|
return [
|
|
{name: "Seven Color Cross Fade SLOW", id: "slow-seven_color_cross_fade"},
|
|
{name: "Seven Color Strobe Flash SLOW", id: "slow-seven_color_strobe_flash"},
|
|
{name: "Strobe SLOW", id: "slow-white_strobe_flash"},
|
|
{name: "Seven Color Jump SLOW", id: "slow-seven_color_jumping"},
|
|
|
|
{name: "Seven Color Cross Fade MEDIUM", id: "medium-seven_color_cross_fade"},
|
|
{name: "Seven Color Strobe Flash MEDIUM", id: "medium-seven_color_strobe_flash"},
|
|
{name: "Strobe MEDIUM", id: "medium-white_strobe_flash"},
|
|
{name: "Seven Color Jump MEDIUM", id: "medium-seven_color_jumping"},
|
|
|
|
{name: "Seven Color Cross Fade FAST", id: "fast-seven_color_cross_fade"},
|
|
{name: "Seven Color Strobe Flash FAST", id: "fast-seven_color_strobe_flash"},
|
|
{name: "Strobe FAST", id: "fast-white_strobe_flash"},
|
|
{name: "Seven Color Jump FAST", id: "fast-seven_color_jumping"}
|
|
];
|
|
}
|
|
|
|
turnOn() {
|
|
let futureState = this.state;
|
|
futureState.on = true;
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
|
|
return this._control.setPower(true).then(success => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
return success;
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
turnOff() {
|
|
let futureState = this.state;
|
|
futureState.on = false;
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
|
|
return this._control.setPower(false).then(success => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
return success;
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
togglePower() {
|
|
if(this.state.on) {
|
|
return this.turnOff();
|
|
} else {
|
|
return this.turnOn();
|
|
}
|
|
}
|
|
|
|
setBrightness(brightness) {
|
|
let futureState = this.state;
|
|
futureState.brightness = brightness;
|
|
futureState.effect = "none";
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
|
|
let { red, green, blue } = utils.HSL_to_RGB(futureState.color);
|
|
|
|
return this._control.setColorWithBrightness(red, green, blue, futureState.brightness).then(success => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
return success;
|
|
}).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);
|
|
|
|
let { red, green, blue } = utils.HSL_to_RGB(futureState.color);
|
|
|
|
return this._control.setColorWithBrightness(red, green, blue, futureState.brightness).then(success => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
return success;
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
setEffect(id) {
|
|
let matches = id.match(/([a-z]+)-(([a-zA-Z]|_)+)/);
|
|
|
|
let speed = 60;
|
|
let effect = "none";
|
|
|
|
if(matches != null) {
|
|
effect = matches[2];
|
|
switch (matches[1]) {
|
|
case 'slow':
|
|
speed = 20;
|
|
break;
|
|
case 'fast':
|
|
speed = 95;
|
|
break;
|
|
case 'medium':
|
|
speed = 50;
|
|
break;
|
|
}
|
|
}
|
|
|
|
let futureState = this.state;
|
|
let promise;
|
|
|
|
if(effect == 'none') {
|
|
futureState.effect = "none";
|
|
|
|
let { red, green, blue } = utils.HSL_to_RGB(futureState.color);
|
|
|
|
promise = this._control.setColorWithBrightness(red, green, blue, futureState.brightness);
|
|
} else {
|
|
futureState.effect = id; // id is "valid" / can be parsed
|
|
|
|
promise = this._control.setPattern(effect, speed);
|
|
}
|
|
|
|
let suid = this._sumanager.registerUpdate(futureState);
|
|
|
|
return promise.then(success => {
|
|
this._sumanager.confirmUpdate(suid);
|
|
|
|
if (this._sumanager.highestConfirmedId == suid) {
|
|
this.emit("state change", this.state);
|
|
}
|
|
return success;
|
|
}).catch(err => {
|
|
this._sumanager.rejectUpdate(suid);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
pullState() {
|
|
return this._control.queryState().then(status => {
|
|
let currentState = this.state;
|
|
let futureState = currentState.clone();
|
|
|
|
//console.log(status);
|
|
|
|
futureState.on = status.on;
|
|
|
|
let effect = (status.mode != 'color' && status.mode != 'warm_white' && status.mode != 'special') ? status.mode : 'none';
|
|
if(effect != 'none') {
|
|
let speed = (status.speed > 80) ? 'fast' : (status.speed > 30) ? 'medium' : 'slow';
|
|
futureState.effect = speed + '-' + effect;
|
|
} else {
|
|
futureState.effect = 'none';
|
|
}
|
|
|
|
if (futureState.effect == 'none') { // only update color when no effects are playing
|
|
futureState.brightness = extractBrightness(status.color);
|
|
futureState.color = utils.RGB_to_HSL(removeBrightness(status.color));
|
|
}
|
|
|
|
if (currentState.hash != futureState.hash) {
|
|
// the state of the controller has changed externally
|
|
this._sumanager.insertConfirmedState(futureState);
|
|
this.emit("state change", this.state);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = HCMagicHome;
|
|
|
|
function extractBrightness(rgb) {
|
|
let max = Math.max(rgb.red, rgb.green, rgb.blue);
|
|
return (max / 255) * 100;
|
|
}
|
|
|
|
function removeBrightness(rgb) {
|
|
let max = Math.max(rgb.red, rgb.green, rgb.blue);
|
|
let scale = (max > 0) ? 255 / max : 0;
|
|
|
|
return {
|
|
red: rgb.red * scale,
|
|
green: rgb.green * scale,
|
|
blue: rgb.blue * scale,
|
|
};
|
|
}
|
|
|
|
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;
|
|
}
|