12 Commits

Author SHA1 Message Date
417f017f45 Using command line to publish libs
Some checks failed
continuous-integration/drone Build is passing
continuous-integration/drone/push Build is failing
WIP

WIP
2023-01-27 16:11:23 -06:00
9cf8ef3c60 Using gitea npm registry
Some checks failed
continuous-integration/drone Build is failing
WIP

WIP
2023-01-26 17:14:57 -06:00
e1ac0a3a5b Only control wiz lights if they are already on
All checks were successful
continuous-integration/drone Build is passing
2022-10-30 10:47:08 -05:00
e61ec0cc3c Stability fixes
Updating longitude type

Only updating wiz bulb if pilot is not undefined

Fixing issue where lights will turn off after receiving power

Fixing bug where wiz lights would go dark instead of maintaining the current brightness
2022-10-29 13:59:36 -05:00
abb66eb26f Bump wiz-lib
All checks were successful
continuous-integration/drone/push Build is passing
2022-09-07 22:10:50 -05:00
c378e46cb3 Making default cron schedule configurable
All checks were successful
continuous-integration/drone/push Build is passing
asdf
2022-09-07 22:04:17 -05:00
a9833729f7 Fixing bugs
All checks were successful
continuous-integration/drone/push Build is passing
- Only RGB lights
- Fixing on/off bug
2022-09-07 21:41:26 -05:00
51b82fc8d2 Updating config schema
All checks were successful
continuous-integration/drone/push Build is passing
asdf
2022-09-07 14:45:36 -05:00
feb5533419 Adding new features
All checks were successful
continuous-integration/drone/push Build is passing
- Adding ability to specify delay times per light
- Adding config.schema.json
2022-09-07 14:29:51 -05:00
8fbfc51276 Bump wiz-lib
All checks were successful
continuous-integration/drone/push Build is passing
Bump
2022-09-06 20:44:31 -05:00
c79b776ec5 Publishing bin dir
All checks were successful
continuous-integration/drone/push Build is passing
2022-09-06 20:33:25 -05:00
da83a94742 Squashed commit of the following:
All checks were successful
continuous-integration/drone/push Build is passing
commit 440a4d62a1
Author: Brandon Watson <brandon@watsonlabs.net>
Date:   Tue Sep 6 20:23:31 2022 -0500

    Fixing issue where button becomes unresponsive | Updating homebridge

commit d73dead5d4
Author: Brandon Watson <brandon@watsonlabs.net>
Date:   Tue Sep 6 18:25:38 2022 -0500

    Successfully controlling wiz bulbs
2022-09-06 20:28:49 -05:00
9 changed files with 557 additions and 442 deletions

View File

@ -28,14 +28,14 @@ steps:
- master - master
- name: publish pre - name: publish pre
image: plugins/npm:1.0.0 image: node
settings: environment:
username: token:
from_secret: npm_username from_secret: npm_token
password: commands:
from_secret: npm_password - npm config set @watsonb8:registry https://gitea.watsonlabs.net/api/packages/watsonb8/npm/
email: b.watson@watsonlabs.net - npm config set -- '//gitea.watsonlabs.net/api/packages/watsonb8/npm/:_authToken' "$token"
registry: "http://10.44.1.6:4873/" - npm publish
when: when:
event: event:
exclude: exclude:
@ -46,14 +46,14 @@ steps:
- master - master
- name: publish tagged version - name: publish tagged version
image: plugins/npm:1.0.0 image: node
settings: environment:
username: token:
from_secret: npm_username from_secret: npm_token
password: commands:
from_secret: npm_password - npm config set @watsonb8:registry https://gitea.watsonlabs.net/api/packages/watsonb8/npm/
email: b.watson@watsonlabs.net - npm config set -- '//gitea.watsonlabs.net/api/packages/watsonb8/npm/:_authToken' "$token"
registry: "http://10.44.1.6:4873/" - npm publish
when: when:
event: event:
- tag - tag
@ -92,7 +92,7 @@ steps:
from_secret: ssh_key from_secret: ssh_key
port: 22 port: 22
script: script:
- npm install -g @watsonb8/homebridge-flux --registry http://10.44.1.6:4873 - npm install -g @watsonb8/homebridge-flux --registry https://gitea.watsonlabs.net
when: when:
event: event:
- tag - tag

139
config.schema.json Normal file
View File

@ -0,0 +1,139 @@
{
"pluginAlias": "Flux",
"pluginType": "platform",
"singular": true,
"schema": {
"type": "object",
"properties": {
"name": {
"title": "Switch Name",
"type": "string",
"required": true
},
"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": "number",
"required": true
},
"testNowDateString": {
"title": "Test Date Time",
"type": "string",
"required": false
},
"hueLights": {
"title": "Hue Lights",
"type": "array",
"uniqueItems": true,
"items": {
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string",
"required": true
},
"cron": {
"title": "Cron Schedule",
"type": "string",
"required": false
},
"on": {
"title": "On",
"type": "boolean",
"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": "Cron Schedule",
"type": "string",
"required": false
},
"on": {
"title": "On",
"type": "boolean",
"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
},
"cron": {
"title": "Default Cron",
"type": "string",
"required": false
}
}
},
"form": null,
"display": null
}

14
package-lock.json generated
View File

@ -11,7 +11,7 @@
"dependencies": { "dependencies": {
"@types/node-cron": "^2.0.3", "@types/node-cron": "^2.0.3",
"@types/suncalc": "^1.8.0", "@types/suncalc": "^1.8.0",
"@watsonb8/wiz-lib": "^1.0.1-62427.0", "@watsonb8/wiz-lib": "^1.0.1-e1c84.0",
"node-cron": "^2.0.3", "node-cron": "^2.0.3",
"node-hue-api": "^4.0.5", "node-hue-api": "^4.0.5",
"suncalc": "^1.8.0" "suncalc": "^1.8.0"
@ -119,9 +119,9 @@
"integrity": "sha512-XLD/llTSB6EBe3thkN+/I0L+yCTB6sjrcVovQdx2Cnl6N6bTzHmwe/J8mWnsXFgxLrj/emzdv8IR4evKYG2qxQ==" "integrity": "sha512-XLD/llTSB6EBe3thkN+/I0L+yCTB6sjrcVovQdx2Cnl6N6bTzHmwe/J8mWnsXFgxLrj/emzdv8IR4evKYG2qxQ=="
}, },
"node_modules/@watsonb8/wiz-lib": { "node_modules/@watsonb8/wiz-lib": {
"version": "1.0.1-8d131.0", "version": "1.0.1-e1c84.0",
"resolved": "http://10.44.1.6:4873/@watsonb8%2fwiz-lib/-/wiz-lib-1.0.1-8d131.0.tgz", "resolved": "http://10.44.1.6:4873/@watsonb8%2fwiz-lib/-/wiz-lib-1.0.1-e1c84.0.tgz",
"integrity": "sha1-kpO4hhhRT4oBKq8fEDwyJC+KwVg=", "integrity": "sha1-3dEF3v2j/oS7ezEBGCfq8wIhBng=",
"dependencies": { "dependencies": {
"dgram": "^1.0.1", "dgram": "^1.0.1",
"getmac": "^5.20.0", "getmac": "^5.20.0",
@ -1967,9 +1967,9 @@
"integrity": "sha512-XLD/llTSB6EBe3thkN+/I0L+yCTB6sjrcVovQdx2Cnl6N6bTzHmwe/J8mWnsXFgxLrj/emzdv8IR4evKYG2qxQ==" "integrity": "sha512-XLD/llTSB6EBe3thkN+/I0L+yCTB6sjrcVovQdx2Cnl6N6bTzHmwe/J8mWnsXFgxLrj/emzdv8IR4evKYG2qxQ=="
}, },
"@watsonb8/wiz-lib": { "@watsonb8/wiz-lib": {
"version": "1.0.1-8d131.0", "version": "1.0.1-e1c84.0",
"resolved": "http://10.44.1.6:4873/@watsonb8%2fwiz-lib/-/wiz-lib-1.0.1-8d131.0.tgz", "resolved": "http://10.44.1.6:4873/@watsonb8%2fwiz-lib/-/wiz-lib-1.0.1-e1c84.0.tgz",
"integrity": "sha1-kpO4hhhRT4oBKq8fEDwyJC+KwVg=", "integrity": "sha1-3dEF3v2j/oS7ezEBGCfq8wIhBng=",
"requires": { "requires": {
"dgram": "^1.0.1", "dgram": "^1.0.1",
"getmac": "^5.20.0", "getmac": "^5.20.0",

View File

@ -1,11 +1,16 @@
{ {
"name": "@watsonb8/homebridge-flux", "name": "@watsonb8/homebridge-flux",
"version": "1.1.3", "version": "1.1.4",
"description": "", "description": "",
"main": "bin/index.js", "main": "bin/index.js",
"publishConfig": { "publishConfig": {
"registry": "http://10.44.1.6:4873/" "registry": "https://gitea.watsonlabs.net"
}, },
"files": [
"bin",
"src",
"config.schema.json"
],
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
@ -29,7 +34,7 @@
"dependencies": { "dependencies": {
"@types/node-cron": "^2.0.3", "@types/node-cron": "^2.0.3",
"@types/suncalc": "^1.8.0", "@types/suncalc": "^1.8.0",
"@watsonb8/wiz-lib": "^1.0.1-62427.0", "@watsonb8/wiz-lib": "^1.0.1-e1c84.0",
"node-cron": "^2.0.3", "node-cron": "^2.0.3",
"node-hue-api": "^4.0.5", "node-hue-api": "^4.0.5",
"suncalc": "^1.8.0" "suncalc": "^1.8.0"

View File

@ -6,11 +6,12 @@ import { IConfig } from "./models/iConfig";
//@ts-ignore //@ts-ignore
import { GetTimesResult, getTimes } from "suncalc"; import { GetTimesResult, getTimes } from "suncalc";
import HueError = require("node-hue-api/lib/HueError"); 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 { WizBulb } from "@watsonb8/wiz-lib/build/wizBulb";
import { colorTemperature2rgb, RGB } from "@watsonb8/wiz-lib"; import { colorTemperature2rgb, RGB } from "@watsonb8/wiz-lib";
import { PlatformAccessory } from "homebridge"; import { PlatformAccessory } from "homebridge";
import { Platform } from "./platform"; import { Platform } from "./platform";
import { colorTempToRgb } from "./util/colorUtil";
const SECONDS_IN_DAY = 86400000; const SECONDS_IN_DAY = 86400000;
const MINUTES_IN_MILLISECOND = 60000; const MINUTES_IN_MILLISECOND = 60000;
@ -29,6 +30,10 @@ export class FluxAccessory {
private readonly _accessory: PlatformAccessory; private readonly _accessory: PlatformAccessory;
private _config: IConfig; private _config: IConfig;
private _isActive: boolean; private _isActive: boolean;
private _hueRGB: RGB;
private _wizRGB: RGB;
private _fade: number;
private _cron: string;
//Service fields //Service fields
private _switchService; private _switchService;
@ -39,6 +44,7 @@ export class FluxAccessory {
private _wizLights: Array<WizBulb> = []; private _wizLights: Array<WizBulb> = [];
private _times: GetTimesResult; private _times: GetTimesResult;
private _tasks: Array<ScheduledTask> = [];
constructor(props: IFluxProps) { constructor(props: IFluxProps) {
//Assign class variables //Assign class variables
@ -47,6 +53,12 @@ export class FluxAccessory {
this._config = props.config; this._config = props.config;
this._isActive = false; this._isActive = false;
this._wizLights = props.wizBulbs; 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._cron = this._config.cron ?? "*/30 * * * * *";
this._times = getTimes( this._times = getTimes(
new Date(), new Date(),
@ -70,8 +82,20 @@ export class FluxAccessory {
} }
).start(); ).start();
this._hue = props.hue; //Schedule job to refresh hues every minute
this.name = this._config.name; this.updateRGB();
cron.schedule(
"* * * * *",
() => {
this.updateRGB();
this._platform.log.info("Updated hues");
},
{
scheduled: true,
}
).start();
this.scheduleLights();
this._accessory this._accessory
.getService(this._platform.api.hap.Service.AccessoryInformation)! .getService(this._platform.api.hap.Service.AccessoryInformation)!
@ -106,6 +130,8 @@ export class FluxAccessory {
.on("set", this.onSetEnabled) .on("set", this.onSetEnabled)
//@ts-ignore //@ts-ignore
.on("get", this.onGetEnabled); .on("get", this.onGetEnabled);
// this.test();
} }
public name: string = "Flux"; public name: string = "Flux";
@ -126,9 +152,11 @@ export class FluxAccessory {
this._config.latitude, this._config.latitude,
this._config.longitude this._config.longitude
); );
this.update(); this._isActive = true;
this.enable();
} else { } else {
this._isActive = false; this._isActive = false;
this.disable();
} }
return callback(); return callback();
}; };
@ -148,112 +176,19 @@ export class FluxAccessory {
* Populates internal lights array using the configuration values * Populates internal lights array using the configuration values
*/ */
private getLights = async (): Promise<void> => { private getLights = async (): Promise<void> => {
for (const value of this._config.lights) { for (const value of this._config.hueLights) {
//@ts-ignore //@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); 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 => { private isHueError = (object: any): object is HueError => {
return "_hueError" in object; 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. * Gets adjusted color temperature.
*/ */
@ -283,13 +218,7 @@ export class FluxAccessory {
} }
} }
private update = async (): Promise<void> => { private updateRGB = (): void => {
this._isActive = true;
while (this._isActive) {
if (this._lights.length === 0) {
await this.getLights();
}
const now = this.getNow(); const now = this.getNow();
//Pad start time by an hour before sunset //Pad start time by an hour before sunset
const start = new Date( const start = new Date(
@ -306,17 +235,11 @@ export class FluxAccessory {
this._times.sunrise.getTime() + 1 * SECONDS_IN_DAY this._times.sunrise.getTime() + 1 * SECONDS_IN_DAY
); );
const startColorTemp = this._config.ceilingColorTemp const startColorTemp = this._config.ceilingColorTemp ?? 4000;
? this._config.ceilingColorTemp const sunsetColorTemp = this._config.sunsetColorTemp ?? 2800;
: 4000; const floorColorTemp = this._config.floorColorTemp ?? 1900;
const sunsetColorTemp = this._config.sunsetColorTemp
? this._config.sunsetColorTemp
: 2800;
const floorColorTemp = this._config.floorColorTemp
? this._config.floorColorTemp
: 1900;
let newTemp = 0; let newTemp = this._config.ceilingColorTemp;
if (start < now && now < sunsetStart) { if (start < now && now < sunsetStart) {
newTemp = this.getTempOffset( newTemp = this.getTempOffset(
@ -338,29 +261,144 @@ export class FluxAccessory {
newTemp = this._config.floorColorTemp; newTemp = this._config.floorColorTemp;
} }
//Set lights //Set RGB
const hueRGB = this.colorTempToRgb(newTemp); this._hueRGB = colorTempToRgb(newTemp);
const wizRGB = colorTemperature2rgb(newTemp); this._wizRGB = colorTemperature2rgb(newTemp);
if (hueRGB && newTemp !== 0) { };
const lightState = new LightState();
lightState private scheduleLights = async (): Promise<void> => {
.transitionInMillis( if (this._lights.length === 0) {
this._config.transition ? this._config.transition : 5000 await this.getLights();
) }
.rgb(hueRGB.r ?? 0, hueRGB.g ?? 0, hueRGB.b ?? 0); this._tasks = [...this.getHueTasks(), ...this.getWizTasks()];
await this.setHueLights(lightState); };
await this.setWizLights(
wizRGB, private getHueTasks(): Array<ScheduledTask> {
this._config.transition ? this._config.transition / 1000 : 5 return this._config.hueLights.map((hueLightConfig) => {
); let light = this._lights.find((x) => x.name == hueLightConfig.name);
let schedule: string = hueLightConfig.cron ?? this._cron;
this._platform.log.info( this._platform.log.info(
`Adjusting light temp to ${newTemp}, ${JSON.stringify( `Scheduling task for ${light?.name}: ${schedule}`
hueRGB
)}`
); );
return cron.schedule(
schedule,
async () => {
await this.updateHueLight(
light,
hueLightConfig?.on ?? false
);
this._platform.log.info("Updated hues");
},
{
scheduled: false,
}
);
});
} }
await Sleep(this._config.delay ? this._config.delay : 60000); 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 ?? this._cron;
this._platform.log.info(
`Scheduling task for ${wizBulb.getMac()}: ${schedule}`
);
return cron.schedule(
schedule,
async () => {
await this.updateWizLight(
wizBulb,
wizLightConfig?.on ?? false
);
this._platform.log.info("Updated hues");
},
{
scheduled: false,
}
);
});
}
private updateWizLight = async (
wizBulb: WizBulb,
on: Boolean
): Promise<void> => {
let pilot;
try {
pilot = await wizBulb.get();
} catch (err: any) {
this._platform.log.error(err.message);
}
if (pilot && pilot.state) {
this._platform.log.info(`Adjusting wiz bulb: ${wizBulb.getMac()}`);
await wizBulb.set(
this._wizRGB,
on ? 100 : pilot.dimming,
this._fade
);
}
};
private updateHueLight = async (
hueLight: Light | undefined,
on: Boolean
): 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);
if (on) {
lightState.brightness(100).on(true);
}
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}`);
}
}
};
private enable() {
this._tasks.forEach((task) => task.start());
}
private disable() {
this._tasks.forEach((task) => task.stop());
}
private test = async () => {
for (let i = 2500; i > 0; i--) {
this._platform.log.info(`i: ${i}`);
for (const wizBulb of this._wizLights) {
let pilot;
try {
pilot = await wizBulb.get();
} catch (err: any) {
this._platform.log.error(err.message);
}
this._platform.log.info(
`Adjusting wiz bulb: ${wizBulb.getMac()}`
);
wizBulb.set(colorTemperature2rgb(i), 100, this._fade);
}
await Sleep(100);
} }
}; };
} }

View File

@ -9,138 +9,3 @@ import { Platform } from "./platform";
export = (api: API) => { export = (api: API) => {
api.registerPlatform(PLATFORM_NAME, Platform); api.registerPlatform(PLATFORM_NAME, Platform);
}; };
// import { IConfig } from "./models/iConfig";
// import { v3 } from "node-hue-api";
// import LocalBootstrap = require("node-hue-api/lib/api/http/LocalBootstrap");
// import Api = require("node-hue-api/lib/api/Api");
// import { Sleep } from "./sleep";
// import { IAccessory } from "./models/iAccessory";
// import { FluxAccessory } from "./fluxAccessory";
// import { WizBulb } from "@watsonb8/wiz-lib/build/wizBulb";
// import discover from "@watsonb8/wiz-lib/build/discovery";
// let Accessory: any;
// let Homebridge: any;
// /**
// * Main entry.
// * @param homebridge
// */
// export default function (homebridge: any) {
// Homebridge = homebridge;
// Accessory = homebridge.platformAccessory;
// homebridge.registerPlatform("homebridge-flux", "Flux", FluxPlatform, true);
// }
// class FluxPlatform {
// log: any = {};
// api: any;
// accessoryList: Array<IAccessory> = [];
// config: IConfig;
// hue: Api | undefined;
// constructor(log: any, config: any, api: any) {
// this.log = log;
// this.api = api;
// this.config = config;
// this.log("INFO - Registering Flux platform");
// this.api.on("didFinishLaunching", this.didFinishLaunching.bind(this));
// }
// private connectWiz = async () => {
// if (!this.config) {
// return;
// }
// return await discover();
// };
// private connectHue = async () => {
// if (!this.config) {
// return;
// }
// if (this.config.userName && this.config.clientKey) {
// this.hue = await v3.api
// .createLocal(this.config.ipAddress)
// .connect(
// this.config.userName,
// this.config.clientKey,
// undefined
// );
// this.log("Using existing connection info");
// } else {
// const unauthenticatedApi = await v3.api
// .createLocal(this.config.ipAddress)
// .connect(undefined, undefined, undefined);
// let createdUser;
// let connected = false;
// while (!connected) {
// try {
// this.log("Creating hue user. Push link button");
// createdUser = await unauthenticatedApi.users.createUser(
// "homebridge",
// "HueChase"
// );
// this.hue = await v3.api
// .createLocal(this.config.ipAddress)
// .connect(
// createdUser.username,
// createdUser.clientKey,
// undefined
// );
// this.log("Connected to Hue Bridge");
// this.log(
// `UserName: ${createdUser.username}, ClientKey: ${createdUser.clientkey}`
// );
// connected = true;
// } catch (err: any) {
// if (err.getHueErrorType() === 101) {
// this.log(
// "The Link button on the bridge was not pressed. Please press the Link button and try again."
// );
// Sleep(5000);
// } else {
// this.log(`Unexpected Error: ${err.message}`);
// break;
// }
// }
// }
// }
// };
// /**
// * Handler for didFinishLaunching
// * Happens after constructor
// */
// private didFinishLaunching() {
// this.log(`INFO - Done registering Flux platform`);
// }
// /**
// * Called by homebridge to gather accessories.
// * @param callback
// */
// public accessories = async (
// callback: (accessories: Array<IAccessory>) => void
// ) => {
// //Connect to hue bridge
// await this.connectHue();
// const wizBulbs = await this.connectWiz();
// this.accessoryList.push(
// new FluxAccessory({
// api: this.api,
// log: this.log,
// homebridge: Homebridge,
// hue: this.hue!,
// wizBulbs: wizBulbs ?? [],
// config: this.config,
// })
// );
// callback(this.accessoryList);
// };
// }

View File

@ -17,7 +17,14 @@ export interface IConfig {
/** /**
* The list of lights to affect * The list of lights to affect
*/ */
lights: Array<string>; hueLights: Array<{ name: string; cron?: string; on?: boolean }>;
/**
* The list of wiz lights to affect
*/
wizLights: Array<{ ip: string; mac: string; cron?: string; on?: boolean }>;
wizDiscoveryEnabled: boolean;
/** /**
* The name of the enable switch in homekit * The name of the enable switch in homekit
@ -52,7 +59,7 @@ export interface IConfig {
/** /**
* The number of milliseconds to wait btw updates * The number of milliseconds to wait btw updates
*/ */
delay?: number; cron?: string;
/** /**
* The current formatted date and time to use with testing * The current formatted date and time to use with testing

View File

@ -1,13 +1,11 @@
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 { import {
API, API,
Characteristic,
DynamicPlatformPlugin, DynamicPlatformPlugin,
Logger, Logger,
Logging,
PlatformAccessory, PlatformAccessory,
PlatformConfig, PlatformConfig,
Service,
UnknownContext, UnknownContext,
} from "homebridge"; } from "homebridge";
import { v3 } from "node-hue-api"; import { v3 } from "node-hue-api";
@ -19,6 +17,7 @@ import { Sleep } from "./sleep";
export class Platform implements DynamicPlatformPlugin { export class Platform implements DynamicPlatformPlugin {
private hue: Api | undefined; private hue: Api | undefined;
private wiz: Discover;
private accessory: PlatformAccessory | undefined = undefined; private accessory: PlatformAccessory | undefined = undefined;
private config: IConfig; private config: IConfig;
constructor( constructor(
@ -27,6 +26,7 @@ export class Platform implements DynamicPlatformPlugin {
public readonly api: API public readonly api: API
) { ) {
this.config = config as unknown as IConfig; this.config = config as unknown as IConfig;
this.wiz = new Discover();
this.log.info("INFO - Registering Flux platform"); this.log.info("INFO - Registering Flux platform");
this.api.on("didFinishLaunching", this.didFinishLaunching.bind(this)); this.api.on("didFinishLaunching", this.didFinishLaunching.bind(this));
} }
@ -77,7 +77,27 @@ export class Platform implements DynamicPlatformPlugin {
return; 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()
) &&
bulb.isRGB()
) {
filtered.push(bulb);
}
}
bulbs.push(...filtered);
}
return bulbs;
}; };
private connectHue = async () => { private connectHue = async () => {

41
src/util/colorUtil.ts Normal file
View 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;
};