UNPKG

@wanderxjtu/homebridge-yeelighter

Version:

Yeelight support for Homebridge with particular support of ceiling lights

273 lines 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LightService = exports.isValidValue = exports.convertColorTemperature = exports.powerModeFromColorModeAndActiveMode = exports.EMPTY_ATTRIBUTES = exports.POWERMODE_MOON = exports.POWERMODE_HSV = exports.POWERMODE_CT = exports.POWERMODE_DEFAULT = void 0; const colortools_1 = require("./colortools"); exports.POWERMODE_DEFAULT = 0; exports.POWERMODE_CT = 1; exports.POWERMODE_HSV = 3; exports.POWERMODE_MOON = 5; exports.EMPTY_ATTRIBUTES = { power: false, color_mode: 0, bright: 0, hue: 0, sat: 0, ct: 0, bg_power: false, bg_bright: 0, bg_hue: 0, bg_sat: 0, bg_ct: 0, bg_lmode: 0, nl_br: 0, active_mode: 0, name: "unknown", }; function powerModeFromColorModeAndActiveMode(color_mode, active_mode) { // PowerMode: // 0: Normal turn on operation(default value) // 1: Turn on and switch to CT mode. (used for white lights) // 2: Turn on and switch to RGB mode. (never used here) // 3: Turn on and switch to HSV mode. (used for color lights) // 4: Turn on and switch to color flow mode. // 5: Turn on and switch to Night light mode. (Ceiling light only). // ColorMode: // 1 means color mode, (rgb -- never used here) // 2 means color temperature mode, (CT used for white light) // 3 means HSV mode (used for color lights) if (active_mode === 1) { return exports.POWERMODE_MOON; } switch (color_mode) { case 1: // this is never used return exports.POWERMODE_DEFAULT; case 2: return exports.POWERMODE_CT; case 3: return exports.POWERMODE_HSV; default: // this should never happen! return exports.POWERMODE_DEFAULT; } } exports.powerModeFromColorModeAndActiveMode = powerModeFromColorModeAndActiveMode; function convertColorTemperature(value) { return Math.round(1000000 / value); } exports.convertColorTemperature = convertColorTemperature; function isValidValue(value) { switch (typeof value) { case "boolean": return true; case "number": return Number.isFinite(value); case "string": return true; default: return false; } } exports.isValidValue = isValidValue; class LightService { constructor(parameters, subtype) { var _a; this.subtype = subtype; this.log = (message, ...optionalParameters) => { this.platform.log.info(`${this.logPrefix} ${message}`, optionalParameters); }; this.warn = (message, ...optionalParameters) => { this.platform.log.warn(`${this.logPrefix} ${message}`, optionalParameters); }; this.error = (message, ...optionalParameters) => { this.platform.log.error(`${this.logPrefix} ${message}`, optionalParameters); }; this.debug = (message, ...optionalParameters) => { if (this.light.detailedLogging) { this.platform.log.info(`${this.logPrefix} ${message}`, optionalParameters); } else { this.platform.log.debug(`${this.logPrefix} ${message}`, optionalParameters); } }; this.onPowerOff = () => { this.updateCharacteristic(this.platform.Characteristic.On, false); }; this.platform = parameters.platform; this.accessory = parameters.accessory; this.light = parameters.light; // we use powerMode to store the currently set mode switch (this.light.info.color_mode) { case 2: this.powerMode = exports.POWERMODE_CT; break; case 3: this.powerMode = exports.POWERMODE_HSV; break; default: // this should never happen! this.powerMode = exports.POWERMODE_DEFAULT; break; } this.name = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.name) || this.device.info.id; // get the LightBulb service if it exists, otherwise create a new LightBulb service // we create multiple services for lights that have a subtype set if (subtype) { const subtypeUid = `${this.light.info.id}#${subtype}`; this.log(`registering subtype ${subtypeUid}`); this.service = this.accessory.getService(subtypeUid) || this.accessory.addService(this.platform.Service.Lightbulb, `${this.name} ${subtype}`, subtypeUid); } else { this.log(`no subtype`); this.service = this.accessory.getService(this.platform.Service.Lightbulb) || this.accessory.addService(this.platform.Service.Lightbulb); } // name handling this.service.getCharacteristic(this.platform.Characteristic.ConfiguredName).on("set", (value, callback) => { this.log("setConfiguredName", value); const name = value.toString(); this.service.displayName = name; this.name = name; this.service.setCharacteristic(this.platform.Characteristic.Name, value); this.platform.api.updatePlatformAccessories([this.accessory]); callback(); }); } get detailedLogging() { return this.light.detailedLogging; } updateName(value) { this.log("Ingoring updateName", value); // this.name = value; // this.service.setCharacteristic(this.platform.Characteristic.Name, `${value} ${this.subtype}`); // this.platform.api.updatePlatformAccessories([this.accessory]); } get device() { return this.light.device; } get logPrefix() { if (this.subtype) { return `[${this.name}#${this.subtype}]`; } return `[${this.name}]`; } get config() { const override = (this.platform.config.override || []); const { info } = this.device; const overrideConfig = override.find(item => item.id === info.id); return overrideConfig || { id: info.id }; } get specs() { return this.light.specs; } async attributes() { return this.light.getAttributes(); } async getAttribute(attribute) { // this should never throw const a = await this.attributes(); return a[attribute]; } setAttributes(attributes) { this.light.setAttributes(attributes); } handleCharacteristic(uuid, getter, setter) { const characteristic = this.service.getCharacteristic(uuid); if (!characteristic) { throw new Error("Could not get Characteristic"); } characteristic.on("get", async (callback) => { if (this.light.connected) { callback(undefined, await getter()); } else { callback(new Error("light disconnected")); } }); characteristic.on("set", async (value, callback) => { if (this.light.connected && isValidValue(value)) { await setter(value); callback(); } else { this.log(`failed to set to value`, value, this.light.connected); callback(new Error("light disconnected or invalid value")); } }); return characteristic; } async updateCharacteristic(uuid, value) { const characteristic = this.service.getCharacteristic(uuid); if (!characteristic) { return Promise.reject(); } if (isValidValue(value)) { characteristic.updateValue(value); } else { this.error("updateCharacteristic value is not finite", value); } } async sendCommandPromiseWithErrorHandling(method, parameters) { try { await this.light.sendCommandPromise(method, parameters); } catch (error) { // catch all errors so Homebridge doesn't crash this.warn("Command failed", error); } } async sendCommand(method, parameters) { return this.sendCommandPromiseWithErrorHandling(method, parameters); } async sendSuddenCommand(method, parameter) { return this.sendCommandPromiseWithErrorHandling(method, [parameter, "sudden", 0]); } async sendSmoothCommand(method, parameter) { return this.sendCommandPromiseWithErrorHandling(method, [parameter, "smooth", 500]); } saveDefaultIfNeeded() { var _a; if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.saveDefault) { this.sendCommand("set_default", []); } } async ensurePowerMode(mode, prefix = "") { if (this.powerMode !== mode) { await this.sendCommand(`${prefix}set_power`, ["on", "sudden", 0, mode]); this.powerMode = mode; if (prefix == "bg") { this.setAttributes({ bg_power: true }); } else { this.setAttributes({ power: true, active_mode: mode == exports.POWERMODE_MOON ? 1 : 0 }); } } } async setHSV(prefix = "") { const hue = this.lastHue; const sat = this.lastSat; if (hue && sat) { await this.ensurePowerMode(exports.POWERMODE_HSV, prefix); const hsv = [hue, sat, "sudden", 0]; delete this.lastHue; delete this.lastSat; await this.sendCommand(`${prefix}set_hsv`, hsv); if (prefix == "bg") { this.setAttributes({ bg_hue: hue, bg_sat: sat }); } else { this.setAttributes({ hue, sat }); } this.saveDefaultIfNeeded(); } } updateColorFromCT(value) { const { h, s } = (0, colortools_1.convertHomeKitColorTemperatureToHomeKitColor)(value); this.service.getCharacteristic(this.platform.Characteristic.Hue).updateValue(h); this.service.getCharacteristic(this.platform.Characteristic.Saturation).updateValue(s); } } exports.LightService = LightService; //# sourceMappingURL=lightservice.js.map