@wanderxjtu/homebridge-yeelighter
Version:
Yeelight support for Homebridge with particular support of ceiling lights
273 lines • 10.3 kB
JavaScript
"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