diff --git a/src/fluxAccessory.ts b/src/fluxAccessory.ts index 899e904..fb988e8 100644 --- a/src/fluxAccessory.ts +++ b/src/fluxAccessory.ts @@ -11,6 +11,7 @@ import HueError = require("node-hue-api/lib/HueError"); let Service: HAPNodeJS.Service; let Characteristic: HAPNodeJS.Characteristic; const SECONDS_IN_DAY = 86400000; +const MINUTES_IN_MILLISECOND = 60000; const SECONDS_IN_HOUR = 3600; export interface IFluxProps { @@ -53,8 +54,6 @@ export class FluxAccessory implements IAccessory { this._times = getTimes(new Date(), this._config.latitude, this._config.longitude); - this.getLights(); - this.platformAccessory = new this._homebridge.platformAccessory(this.name, this.generateUUID(), this._homebridge.hap.Accessory.Categories.SWITCH); //@ts-ignore @@ -192,6 +191,28 @@ export class FluxAccessory implements IAccessory { }); } + /** + * Gets adjusted color temperature. + */ + private getTempOffset = (startTemp: number, endTemp: number, startTime: Date, endTime: Date) => { + const now = this.getNow().getTime() + const percentComplete = ((now - startTime.getTime()) / (endTime.getTime() - startTime.getTime())); + const tempRange = Math.abs(startTemp - endTemp); + const tempOffset = tempRange * percentComplete + return startTemp - tempOffset; + } + + /** + * Get the current time. Use test time if present. + */ + private getNow() { + if (this._config.testNowDateString) { + return new Date(this._config.testNowDateString); + } else { + return new Date(); + } + } + private update = async (): Promise => { this._isActive = true; while (this._isActive) { @@ -199,39 +220,28 @@ export class FluxAccessory implements IAccessory { await this.getLights(); } - const now = new Date(Date.now()); + const now = this.getNow(); //Pad start time by an hour before sunset - const start = new Date(this._times.sunset.getTime() - 3 * 1000 * SECONDS_IN_HOUR); - const end = new Date(this._times.sunrise.getTime() + 1 * SECONDS_IN_DAY); - // const sunset = new Date('Wed, 15 Apr 2020 21:00:00 GMT'); - // const sunrise = new Date('Wed, 15 Apr 2020 23:00:00 GMT'); + const start = new Date(this._times.sunset.getTime() - (30 * 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() + 30 * MINUTES_IN_MILLISECOND); + const sunrise = new Date(this._times.sunrise.getTime() + 1 * SECONDS_IN_DAY); - const startColorTemp = this._config.startColorTemp ? this._config.startColorTemp : 4000; - const stopColorTemp = this._config.stopColorTemp ? this._config.stopColorTemp : 1900; + 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 percentageComplete = 0; let newTemp = 0; - const midTime = (end.getTime() - start.getTime()) / 2; - const mid = new Date(new Date().setTime(start.getTime() + midTime)); - const tempRange = Math.abs(startColorTemp - stopColorTemp); - - if ((start < now) && (now < mid)) { - //Before sunset; calculate temp based on TOD - const totalDecreaseTime = (mid.getTime() - start.getTime()) / 1000; - const secondsFromStart = (now.getTime() - start.getTime()) / 1000; - percentageComplete = secondsFromStart / totalDecreaseTime; - const tempOffset = tempRange * percentageComplete; - - newTemp = startColorTemp - tempOffset; - } else if ((mid < now) && (now < end)) { - //After sunset; calculate temp based on TOD - const totalIncreaseTime = (end.getTime() - mid.getTime()) / 1000; - const secondsUntilSunrise = (end.getTime() - now.getTime()) / 1000; - percentageComplete = secondsUntilSunrise / totalIncreaseTime; - - const tempOffset = tempRange * percentageComplete; - newTemp = startColorTemp - tempOffset; + 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 diff --git a/src/models/iConfig.ts b/src/models/iConfig.ts index e4edae7..c9cd686 100644 --- a/src/models/iConfig.ts +++ b/src/models/iConfig.ts @@ -3,12 +3,59 @@ export interface IConfig { ipAddress: string; userName?: string; clientKey?: string; + + /** + * Latitude + */ latitude: number; + + /** + * Longitute + */ longitude: number; + + /** + * The list of lights to affect + */ lights: Array; + + /** + * The name of the enable switch in homekit + */ name: string; - startColorTemp?: number; - stopColorTemp?: number; + + /** + * The color temperature at the start of sunset transition + */ + ceilingColorTemp: number; + + /** + * The color temp during the night + */ + floorColorTemp: number; + + /** + * The color temp at sunet + */ + sunsetColorTemp: number; + + /** + * The time in milliseconds the lights should remain at sunset temperature. + */ + sunsetDuration: number; + + /** + * The number of milliseconds the lights take to transition + */ transition?: number; + + /** + * The number of milliseconds to wait btw updates + */ delay?: number; + + /** + * The current formatted date and time to use with testing + */ + testNowDateString?: string; } \ No newline at end of file