- Adding ability to specify delay times per light - Adding config.schema.json
This commit is contained in:
parent
8fbfc51276
commit
feb5533419
119
config.schema.json
Normal file
119
config.schema.json
Normal file
@ -0,0 +1,119 @@
|
||||
{
|
||||
"pluginAlias": "Flux",
|
||||
"pluginType": "platform",
|
||||
"singular": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ipAddress": {
|
||||
"title": "IP Address",
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"userName": {
|
||||
"title": "User Name",
|
||||
"type": "string",
|
||||
"required": false
|
||||
},
|
||||
"clientKey": {
|
||||
"title": "Client Key",
|
||||
"type": "string",
|
||||
"required": false
|
||||
},
|
||||
"latitude": {
|
||||
"title": "Latitude",
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"longitude": {
|
||||
"title": "Longitude",
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"hueLights": {
|
||||
"title": "Hue Lights",
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ip": {
|
||||
"title": "Name",
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"cron": {
|
||||
"title": "Poll Delay in MS",
|
||||
"type": "string",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"wizLights": {
|
||||
"title": "Wiz Lights",
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ip": {
|
||||
"title": "Ip Address",
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"mac": {
|
||||
"title": "Mac Address",
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"cron": {
|
||||
"title": "Poll Delay in MS",
|
||||
"type": "string",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
"wizDiscoveryEnabled": {
|
||||
"title": "Wiz Discovery Enabled",
|
||||
"type": "boolean",
|
||||
"required": true
|
||||
},
|
||||
"ceilingColorTemp": {
|
||||
"title": "Ceiling Color Temperature",
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"sunsetColorTemp": {
|
||||
"title": "Sunset Color Temperature",
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"floorColorTemp": {
|
||||
"title": "Floor Color Temperature",
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"sunsetDuration": {
|
||||
"title": "Sunset Duration",
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"transition": {
|
||||
"title": "Transition Time",
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"delay": {
|
||||
"title": "Poll Delay in MS",
|
||||
"type": "number",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"form": null,
|
||||
"display": null
|
||||
}
|
12
package-lock.json
generated
12
package-lock.json
generated
@ -119,9 +119,9 @@
|
||||
"integrity": "sha512-XLD/llTSB6EBe3thkN+/I0L+yCTB6sjrcVovQdx2Cnl6N6bTzHmwe/J8mWnsXFgxLrj/emzdv8IR4evKYG2qxQ=="
|
||||
},
|
||||
"node_modules/@watsonb8/wiz-lib": {
|
||||
"version": "1.0.1-1c687.0",
|
||||
"resolved": "http://10.44.1.6:4873/@watsonb8%2fwiz-lib/-/wiz-lib-1.0.1-1c687.0.tgz",
|
||||
"integrity": "sha1-dag89Ke1YURYSIwyWkQM/lCbvPI=",
|
||||
"version": "1.0.1-9548b.0",
|
||||
"resolved": "http://10.44.1.6:4873/@watsonb8%2fwiz-lib/-/wiz-lib-1.0.1-9548b.0.tgz",
|
||||
"integrity": "sha1-PL/Phi0KQ5DJGRspSHA+i1lprp4=",
|
||||
"dependencies": {
|
||||
"dgram": "^1.0.1",
|
||||
"getmac": "^5.20.0",
|
||||
@ -1967,9 +1967,9 @@
|
||||
"integrity": "sha512-XLD/llTSB6EBe3thkN+/I0L+yCTB6sjrcVovQdx2Cnl6N6bTzHmwe/J8mWnsXFgxLrj/emzdv8IR4evKYG2qxQ=="
|
||||
},
|
||||
"@watsonb8/wiz-lib": {
|
||||
"version": "1.0.1-1c687.0",
|
||||
"resolved": "http://10.44.1.6:4873/@watsonb8%2fwiz-lib/-/wiz-lib-1.0.1-1c687.0.tgz",
|
||||
"integrity": "sha1-dag89Ke1YURYSIwyWkQM/lCbvPI=",
|
||||
"version": "1.0.1-9548b.0",
|
||||
"resolved": "http://10.44.1.6:4873/@watsonb8%2fwiz-lib/-/wiz-lib-1.0.1-9548b.0.tgz",
|
||||
"integrity": "sha1-PL/Phi0KQ5DJGRspSHA+i1lprp4=",
|
||||
"requires": {
|
||||
"dgram": "^1.0.1",
|
||||
"getmac": "^5.20.0",
|
||||
|
@ -8,7 +8,8 @@
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"src"
|
||||
"src",
|
||||
"config.schema.json"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
|
@ -6,11 +6,12 @@ import { IConfig } from "./models/iConfig";
|
||||
//@ts-ignore
|
||||
import { GetTimesResult, getTimes } from "suncalc";
|
||||
import HueError = require("node-hue-api/lib/HueError");
|
||||
import cron from "node-cron";
|
||||
import cron, { ScheduledTask } from "node-cron";
|
||||
import { WizBulb } from "@watsonb8/wiz-lib/build/wizBulb";
|
||||
import { colorTemperature2rgb, RGB } from "@watsonb8/wiz-lib";
|
||||
import { PlatformAccessory } from "homebridge";
|
||||
import { Platform } from "./platform";
|
||||
import { colorTempToRgb } from "./util/colorUtil";
|
||||
|
||||
const SECONDS_IN_DAY = 86400000;
|
||||
const MINUTES_IN_MILLISECOND = 60000;
|
||||
@ -29,6 +30,9 @@ export class FluxAccessory {
|
||||
private readonly _accessory: PlatformAccessory;
|
||||
private _config: IConfig;
|
||||
private _isActive: boolean;
|
||||
private _hueRGB: RGB;
|
||||
private _wizRGB: RGB;
|
||||
private _fade: number;
|
||||
|
||||
//Service fields
|
||||
private _switchService;
|
||||
@ -39,6 +43,7 @@ export class FluxAccessory {
|
||||
private _wizLights: Array<WizBulb> = [];
|
||||
|
||||
private _times: GetTimesResult;
|
||||
private _tasks: Array<ScheduledTask> = [];
|
||||
|
||||
constructor(props: IFluxProps) {
|
||||
//Assign class variables
|
||||
@ -47,6 +52,11 @@ export class FluxAccessory {
|
||||
this._config = props.config;
|
||||
this._isActive = false;
|
||||
this._wizLights = props.wizBulbs;
|
||||
this._hue = props.hue;
|
||||
this.name = this._config.name;
|
||||
this._hueRGB = { r: 0, g: 0, b: 0 };
|
||||
this._wizRGB = { r: 0, g: 0, b: 0 };
|
||||
this._fade = this._config.transition ?? 30000;
|
||||
|
||||
this._times = getTimes(
|
||||
new Date(),
|
||||
@ -70,8 +80,20 @@ export class FluxAccessory {
|
||||
}
|
||||
).start();
|
||||
|
||||
this._hue = props.hue;
|
||||
this.name = this._config.name;
|
||||
//Schedule job to refresh hues every minute
|
||||
this.updateRGB();
|
||||
cron.schedule(
|
||||
"* * * * *",
|
||||
() => {
|
||||
this.updateRGB();
|
||||
this._platform.log.info("Updated hues");
|
||||
},
|
||||
{
|
||||
scheduled: true,
|
||||
}
|
||||
).start();
|
||||
|
||||
this.scheduleLights();
|
||||
|
||||
this._accessory
|
||||
.getService(this._platform.api.hap.Service.AccessoryInformation)!
|
||||
@ -126,9 +148,11 @@ export class FluxAccessory {
|
||||
this._config.latitude,
|
||||
this._config.longitude
|
||||
);
|
||||
this.update();
|
||||
this._isActive = true;
|
||||
this.enable();
|
||||
} else {
|
||||
this._isActive = false;
|
||||
this.disable();
|
||||
}
|
||||
return callback();
|
||||
};
|
||||
@ -148,112 +172,19 @@ export class FluxAccessory {
|
||||
* Populates internal lights array using the configuration values
|
||||
*/
|
||||
private getLights = async (): Promise<void> => {
|
||||
for (const value of this._config.lights) {
|
||||
for (const value of this._config.hueLights) {
|
||||
//@ts-ignore
|
||||
const light: Light = await this._hue.lights.getLightByName(value);
|
||||
const light: Light = await this._hue.lights.getLightByName(
|
||||
value.name
|
||||
);
|
||||
this._lights.push(light);
|
||||
}
|
||||
};
|
||||
|
||||
private colorTempToRgb = (kelvin: number): RGB => {
|
||||
var temp = kelvin / 100;
|
||||
var red, green, blue;
|
||||
if (temp <= 66) {
|
||||
red = 255;
|
||||
green = temp;
|
||||
green = 99.4708025861 * Math.log(green) - 161.1195681661;
|
||||
|
||||
if (temp <= 19) {
|
||||
blue = 0;
|
||||
} else {
|
||||
blue = temp - 10;
|
||||
blue = 138.5177312231 * Math.log(blue) - 305.0447927307;
|
||||
}
|
||||
} else {
|
||||
red = temp - 60;
|
||||
red = 329.698727446 * Math.pow(red, -0.1332047592);
|
||||
|
||||
green = temp - 60;
|
||||
green = 288.1221695283 * Math.pow(green, -0.0755148492);
|
||||
|
||||
blue = 255;
|
||||
}
|
||||
return {
|
||||
r: this.clamp(red, 0, 255),
|
||||
g: this.clamp(green, 0, 255),
|
||||
b: this.clamp(blue, 0, 255),
|
||||
};
|
||||
};
|
||||
|
||||
private clamp(x: number, min: number, max: number) {
|
||||
if (x < min) {
|
||||
return min;
|
||||
}
|
||||
if (x > max) {
|
||||
return max;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
private isHueError = (object: any): object is HueError => {
|
||||
return "_hueError" in object;
|
||||
};
|
||||
|
||||
private setHueLights = async (state: LightState) => {
|
||||
const promises: Array<Promise<unknown> | PromiseLike<unknown>> = [];
|
||||
this._lights.map(async (light: Light) => {
|
||||
try {
|
||||
await this._hue.lights.setLightState(light.id, state);
|
||||
} catch (err) {
|
||||
if (
|
||||
this.isHueError(err) &&
|
||||
err.message ===
|
||||
"parameter, xy, is not modifiable. Device is set to off."
|
||||
) {
|
||||
//Eat this
|
||||
} else {
|
||||
this._platform.log.info(
|
||||
`Error while setting lights: ${err}`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
};
|
||||
|
||||
private setWizLights = async (rgb: RGB, fade: number): Promise<void> => {
|
||||
await Promise.all(
|
||||
this._wizLights.map(async (bulb) => {
|
||||
const pilot = await bulb.get();
|
||||
bulb.set(rgb, pilot?.dimming, fade);
|
||||
})
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to generate a UUID
|
||||
*/
|
||||
private generateUUID(): string {
|
||||
// Public Domain/MIT
|
||||
var d = new Date().getTime();
|
||||
if (
|
||||
typeof performance !== "undefined" &&
|
||||
typeof performance.now === "function"
|
||||
) {
|
||||
d += performance.now(); //use high-precision timer if available
|
||||
}
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
|
||||
/[xy]/g,
|
||||
function (c) {
|
||||
var r = (d + Math.random() * 16) % 16 | 0;
|
||||
d = Math.floor(d / 16);
|
||||
return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets adjusted color temperature.
|
||||
*/
|
||||
@ -283,84 +214,142 @@ export class FluxAccessory {
|
||||
}
|
||||
}
|
||||
|
||||
private update = async (): Promise<void> => {
|
||||
this._isActive = true;
|
||||
while (this._isActive) {
|
||||
if (this._lights.length === 0) {
|
||||
await this.getLights();
|
||||
private updateRGB = (): void => {
|
||||
const now = this.getNow();
|
||||
//Pad start time by an hour before sunset
|
||||
const start = new Date(
|
||||
this._times.sunset.getTime() - 60 * MINUTES_IN_MILLISECOND
|
||||
);
|
||||
const sunsetStart = this._times.sunsetStart;
|
||||
const sunsetEnd = new Date(
|
||||
this._times.sunset.getTime() + this._config.sunsetDuration
|
||||
);
|
||||
const nightStart = new Date(
|
||||
sunsetEnd.getTime() + 60 * MINUTES_IN_MILLISECOND
|
||||
);
|
||||
const sunrise = new Date(
|
||||
this._times.sunrise.getTime() + 1 * SECONDS_IN_DAY
|
||||
);
|
||||
|
||||
const startColorTemp = this._config.ceilingColorTemp ?? 4000;
|
||||
const sunsetColorTemp = this._config.sunsetColorTemp ?? 2800;
|
||||
const floorColorTemp = this._config.floorColorTemp ?? 1900;
|
||||
|
||||
let newTemp = 0;
|
||||
|
||||
if (start < now && now < sunsetStart) {
|
||||
newTemp = this.getTempOffset(
|
||||
startColorTemp,
|
||||
sunsetColorTemp,
|
||||
start,
|
||||
sunsetStart
|
||||
);
|
||||
} else if (sunsetStart < now && now < sunsetEnd) {
|
||||
newTemp = this._config.sunsetColorTemp;
|
||||
} else if (sunsetEnd < now && now < nightStart) {
|
||||
newTemp = this.getTempOffset(
|
||||
sunsetColorTemp,
|
||||
floorColorTemp,
|
||||
sunsetEnd,
|
||||
nightStart
|
||||
);
|
||||
} else if (nightStart < now && now < sunrise) {
|
||||
newTemp = this._config.floorColorTemp;
|
||||
}
|
||||
|
||||
//Set RGB
|
||||
this._hueRGB = colorTempToRgb(newTemp);
|
||||
this._wizRGB = colorTemperature2rgb(newTemp);
|
||||
};
|
||||
|
||||
private scheduleLights = async (): Promise<void> => {
|
||||
if (this._lights.length === 0) {
|
||||
await this.getLights();
|
||||
}
|
||||
this._tasks = [...this.getHueTasks(), ...this.getWizTasks()];
|
||||
};
|
||||
|
||||
private getHueTasks(): Array<ScheduledTask> {
|
||||
return this._config.hueLights.map((hueLightConfig) => {
|
||||
let light = this._lights.find((x) => x.name == hueLightConfig.name);
|
||||
let schedule: string = hueLightConfig.cron ?? "*/6 * * * *";
|
||||
this._platform.log.info(
|
||||
`Scheduling task for ${light?.name}: ${schedule}`
|
||||
);
|
||||
return cron.schedule(
|
||||
schedule,
|
||||
async () => {
|
||||
await this.updateHueLight(light);
|
||||
this._platform.log.info("Updated hues");
|
||||
},
|
||||
{
|
||||
scheduled: false,
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private getWizTasks(): Array<ScheduledTask> {
|
||||
return this._wizLights.map((wizBulb) => {
|
||||
let wizLightConfig = this._config.wizLights.find(
|
||||
(x) => x.ip == wizBulb.getIp()
|
||||
);
|
||||
let schedule: string = wizLightConfig?.cron ?? "*/6 * * * *";
|
||||
this._platform.log.info(
|
||||
`Scheduling task for ${wizBulb.getMac()}: ${schedule}`
|
||||
);
|
||||
return cron.schedule(
|
||||
schedule,
|
||||
async () => {
|
||||
await this.updateWizLight(wizBulb);
|
||||
this._platform.log.info("Updated hues");
|
||||
},
|
||||
{
|
||||
scheduled: false,
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private updateWizLight = async (wizBulb: WizBulb): Promise<void> => {
|
||||
const pilot = await wizBulb.get();
|
||||
this._platform.log.info(`Adjusting wiz bulb: ${wizBulb.getMac()}`);
|
||||
wizBulb.set(this._wizRGB, pilot?.dimming, this._fade);
|
||||
};
|
||||
|
||||
private updateHueLight = async (
|
||||
hueLight: Light | undefined
|
||||
): Promise<void> => {
|
||||
if (!hueLight) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._platform.log.info(`Adjusting wiz bulb: ${hueLight.name}`);
|
||||
|
||||
const lightState = new LightState();
|
||||
lightState
|
||||
.transitionInMillis(this._fade)
|
||||
.rgb(this._hueRGB.r ?? 0, this._hueRGB.g ?? 0, this._hueRGB.b ?? 0);
|
||||
try {
|
||||
await this._hue.lights.setLightState(hueLight.id, lightState);
|
||||
} catch (err) {
|
||||
if (
|
||||
this.isHueError(err) &&
|
||||
err.message ===
|
||||
"parameter, xy, is not modifiable. Device is set to off."
|
||||
) {
|
||||
//Eat this
|
||||
} else {
|
||||
this._platform.log.info(`Error while setting lights: ${err}`);
|
||||
}
|
||||
|
||||
const now = this.getNow();
|
||||
//Pad start time by an hour before sunset
|
||||
const start = new Date(
|
||||
this._times.sunset.getTime() - 60 * MINUTES_IN_MILLISECOND
|
||||
);
|
||||
const sunsetStart = this._times.sunsetStart;
|
||||
const sunsetEnd = new Date(
|
||||
this._times.sunset.getTime() + this._config.sunsetDuration
|
||||
);
|
||||
const nightStart = new Date(
|
||||
sunsetEnd.getTime() + 60 * MINUTES_IN_MILLISECOND
|
||||
);
|
||||
const sunrise = new Date(
|
||||
this._times.sunrise.getTime() + 1 * SECONDS_IN_DAY
|
||||
);
|
||||
|
||||
const startColorTemp = this._config.ceilingColorTemp
|
||||
? this._config.ceilingColorTemp
|
||||
: 4000;
|
||||
const sunsetColorTemp = this._config.sunsetColorTemp
|
||||
? this._config.sunsetColorTemp
|
||||
: 2800;
|
||||
const floorColorTemp = this._config.floorColorTemp
|
||||
? this._config.floorColorTemp
|
||||
: 1900;
|
||||
|
||||
let newTemp = 0;
|
||||
|
||||
if (start < now && now < sunsetStart) {
|
||||
newTemp = this.getTempOffset(
|
||||
startColorTemp,
|
||||
sunsetColorTemp,
|
||||
start,
|
||||
sunsetStart
|
||||
);
|
||||
} else if (sunsetStart < now && now < sunsetEnd) {
|
||||
newTemp = this._config.sunsetColorTemp;
|
||||
} else if (sunsetEnd < now && now < nightStart) {
|
||||
newTemp = this.getTempOffset(
|
||||
sunsetColorTemp,
|
||||
floorColorTemp,
|
||||
sunsetEnd,
|
||||
nightStart
|
||||
);
|
||||
} else if (nightStart < now && now < sunrise) {
|
||||
newTemp = this._config.floorColorTemp;
|
||||
}
|
||||
|
||||
//Set lights
|
||||
const hueRGB = this.colorTempToRgb(newTemp);
|
||||
const wizRGB = colorTemperature2rgb(newTemp);
|
||||
if (hueRGB && newTemp !== 0) {
|
||||
const lightState = new LightState();
|
||||
lightState
|
||||
.transitionInMillis(
|
||||
this._config.transition ? this._config.transition : 5000
|
||||
)
|
||||
.rgb(hueRGB.r ?? 0, hueRGB.g ?? 0, hueRGB.b ?? 0);
|
||||
await this.setHueLights(lightState);
|
||||
await this.setWizLights(
|
||||
wizRGB,
|
||||
this._config.transition ? this._config.transition / 1000 : 5
|
||||
);
|
||||
this._platform.log.info(
|
||||
`Adjusting light temp to ${newTemp}, ${JSON.stringify(
|
||||
hueRGB
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
await Sleep(this._config.delay ? this._config.delay : 60000);
|
||||
}
|
||||
};
|
||||
|
||||
private enable() {
|
||||
this._tasks.forEach((task) => task.start());
|
||||
}
|
||||
|
||||
private disable() {
|
||||
this._tasks.forEach((task) => task.stop());
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,14 @@ export interface IConfig {
|
||||
/**
|
||||
* The list of lights to affect
|
||||
*/
|
||||
lights: Array<string>;
|
||||
hueLights: Array<{ name: string; cron?: string }>;
|
||||
|
||||
/**
|
||||
* The list of wiz lights to affect
|
||||
*/
|
||||
wizLights: Array<{ ip: string; mac: string; cron?: string }>;
|
||||
|
||||
wizDiscoveryEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The name of the enable switch in homekit
|
||||
@ -58,4 +65,4 @@ export interface IConfig {
|
||||
* The current formatted date and time to use with testing
|
||||
*/
|
||||
testNowDateString?: string;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import discover from "@watsonb8/wiz-lib/build/discovery";
|
||||
import { Discover } from "@watsonb8/wiz-lib/build/discovery";
|
||||
import { WizBulb } from "@watsonb8/wiz-lib/build/wizBulb";
|
||||
import {
|
||||
API,
|
||||
Characteristic,
|
||||
@ -19,6 +20,7 @@ import { Sleep } from "./sleep";
|
||||
|
||||
export class Platform implements DynamicPlatformPlugin {
|
||||
private hue: Api | undefined;
|
||||
private wiz: Discover;
|
||||
private accessory: PlatformAccessory | undefined = undefined;
|
||||
private config: IConfig;
|
||||
constructor(
|
||||
@ -27,6 +29,7 @@ export class Platform implements DynamicPlatformPlugin {
|
||||
public readonly api: API
|
||||
) {
|
||||
this.config = config as unknown as IConfig;
|
||||
this.wiz = new Discover();
|
||||
this.log.info("INFO - Registering Flux platform");
|
||||
this.api.on("didFinishLaunching", this.didFinishLaunching.bind(this));
|
||||
}
|
||||
@ -77,7 +80,26 @@ export class Platform implements DynamicPlatformPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
return await discover();
|
||||
let bulbs: Array<WizBulb> = await this.wiz.createWizBulbs(
|
||||
this.config.wizLights
|
||||
);
|
||||
|
||||
if (this.config.wizDiscoveryEnabled) {
|
||||
let discoveredBulbs: Array<WizBulb> = await this.wiz.discover();
|
||||
let filtered = [];
|
||||
for (const bulb of discoveredBulbs) {
|
||||
if (
|
||||
!bulbs.some(
|
||||
(manualBulb) => manualBulb.getIp() === bulb.getIp()
|
||||
)
|
||||
) {
|
||||
filtered.push(bulb);
|
||||
}
|
||||
}
|
||||
bulbs.push(...filtered);
|
||||
}
|
||||
|
||||
return bulbs;
|
||||
};
|
||||
|
||||
private connectHue = async () => {
|
||||
|
41
src/util/colorUtil.ts
Normal file
41
src/util/colorUtil.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { RGB } from "@watsonb8/wiz-lib";
|
||||
|
||||
export const colorTempToRgb = (kelvin: number): RGB => {
|
||||
var temp = kelvin / 100;
|
||||
var red, green, blue;
|
||||
if (temp <= 66) {
|
||||
red = 255;
|
||||
green = temp;
|
||||
green = 99.4708025861 * Math.log(green) - 161.1195681661;
|
||||
|
||||
if (temp <= 19) {
|
||||
blue = 0;
|
||||
} else {
|
||||
blue = temp - 10;
|
||||
blue = 138.5177312231 * Math.log(blue) - 305.0447927307;
|
||||
}
|
||||
} else {
|
||||
red = temp - 60;
|
||||
red = 329.698727446 * Math.pow(red, -0.1332047592);
|
||||
|
||||
green = temp - 60;
|
||||
green = 288.1221695283 * Math.pow(green, -0.0755148492);
|
||||
|
||||
blue = 255;
|
||||
}
|
||||
return {
|
||||
r: clamp(red, 0, 255),
|
||||
g: clamp(green, 0, 255),
|
||||
b: clamp(blue, 0, 255),
|
||||
};
|
||||
};
|
||||
|
||||
const clamp = (x: number, min: number, max: number) => {
|
||||
if (x < min) {
|
||||
return min;
|
||||
}
|
||||
if (x > max) {
|
||||
return max;
|
||||
}
|
||||
return x;
|
||||
};
|
Loading…
Reference in New Issue
Block a user