homebridge-virtual-accessories
Version:
Virtual HomeKit accessories for Homebridge.
127 lines • 6.62 kB
JavaScript
/* eslint-disable brace-style */
import { Accessory } from './accessory.js';
import { Timer } from '../utils/timer.js';
import { Utils } from '../utils/utils.js';
/**
* FilterMaintenance - Accessory implementation
*/
export class FilterMaintenance extends Accessory {
static ACCESSORY_TYPE_NAME = 'Filter';
static FILTER_OK = 0; // Characteristic.FilterChangeIndication.FILTER_OK
static CHANGE_FILTER = 1; // Characteristic.FilterChangeIndication.CHANGE_FILTER
timerStartTimeStorageKey = 'TimerStartTime';
timerDurationStorageKey = 'TimerDuration';
timerIsRunningStorageKey = 'TimerIsRunning';
lifespan;
lifespanTimer;
filterChangeIndicator;
states = {};
constructor(platform, accessory, accessoryConfiguration) {
super(platform, accessory, accessoryConfiguration);
// First configure the device based on the accessory details
this.lifespan = Utils.daysHoursMinutesSecondsToSeconds(this.accessoryConfiguration.filterMaintenance.lifespan.days, (this.accessoryConfiguration.filterMaintenance.lifespan.hours ??= 0), (this.accessoryConfiguration.filterMaintenance.lifespan.minutes ??= 0), (this.accessoryConfiguration.filterMaintenance.lifespan.seconds ??= 0));
const timerIsResettable = true;
this.lifespanTimer = new Timer(this.accessoryConfiguration.accessoryName, this.log, timerIsResettable, this.lifespan);
const accessoryState = this.loadAccessoryState(this.storagePath);
if (this.isEmptyAccessoryState(accessoryState)) {
// No stored state -> First run
this.lifespanTimer.start(this.onTimerExpired.bind(this));
this.storeState();
}
else {
const cachedTimerStartTime = accessoryState[this.timerStartTimeStorageKey];
const cachedTimerDuration = accessoryState[this.timerDurationStorageKey];
const cachedTimerIsRunning = accessoryState[this.timerIsRunningStorageKey];
if (this.lifespan === cachedTimerDuration) {
// If the timer was running, calculate elapsed time and set timer for remaining duration
if (cachedTimerIsRunning) {
Utils.restoreRunningTimer(this.lifespanTimer, cachedTimerStartTime, cachedTimerDuration, this.onTimerExpired.bind(this), this.accessoryConfiguration.accessoryName, this.log);
// Do not store state if the timer was restored!
// Store state only when the timer started or reset
}
}
else {
// eslint-disable-next-line max-len
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Lifespan was changed from: ${cachedTimerDuration} to: ${this.lifespan}. Restart the timer`);
// The lifetime was changed, restart the timer
this.lifespanTimer.start(this.onTimerExpired.bind(this));
this.storeState();
}
}
this.filterChangeIndicator = this.lifespanTimer?.isTimerRunning() ? FilterMaintenance.FILTER_OK : FilterMaintenance.CHANGE_FILTER;
this.service = this.accessory.getService(this.platform.Service.FilterMaintenance) || this.accessory.addService(this.platform.Service.FilterMaintenance);
this.service.setCharacteristic(this.platform.Characteristic.Name, this.accessoryConfiguration.accessoryName);
this.service.getCharacteristic(this.platform.Characteristic.FilterChangeIndication)
.onGet(this.getFilterChangeIndication.bind(this));
this.service.getCharacteristic(this.platform.Characteristic.FilterLifeLevel)
.onGet(this.getFilterLifeLevel.bind(this));
this.service.getCharacteristic(this.platform.Characteristic.ResetFilterIndication)
.onSet(this.setResetFilterIndication.bind(this));
}
// Handlers
async getFilterChangeIndication() {
const filterChangeIndicator = this.filterChangeIndicator;
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Filter Change Indication: ${FilterMaintenance.getStateName(filterChangeIndicator)}`);
return filterChangeIndicator;
}
async getFilterLifeLevel() {
const filterLifeLevel = this.lifespanTimer.getRemainingDuration() / this.lifespan * 100;
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Filter Life Level: ${filterLifeLevel.toFixed(2)}%`);
return filterLifeLevel;
}
async setResetFilterIndication(value) {
const reset = value;
if (reset === 1) {
this.lifespanTimer.stop();
this.lifespanTimer.start(this.onTimerExpired.bind(this));
this.filterChangeIndicator = FilterMaintenance.FILTER_OK;
this.storeState();
this.log.info(`[${this.accessoryConfiguration.accessoryName}] Reset Filter Indication`);
}
else {
this.log.error(`[${this.accessoryConfiguration.accessoryName}] Reset Filter Indication called with invalid value ${reset}`);
}
}
getJsonState() {
const timerStartTime = this.lifespanTimer.getStartTime().toString();
const timerDuration = (this.lifespanTimer.getRuntime() > 0) ? this.lifespanTimer.getRuntime() : this.lifespanTimer.getDefaultDuration();
const timerIsRunning = this.lifespanTimer.isTimerRunning();
const jsonState = {
[this.timerStartTimeStorageKey]: timerStartTime,
[this.timerDurationStorageKey]: timerDuration,
[this.timerIsRunningStorageKey]: timerIsRunning,
};
const json = JSON.stringify(jsonState);
return json;
}
getAccessoryTypeName() {
return FilterMaintenance.ACCESSORY_TYPE_NAME;
}
static getStateName(event) {
let stateName;
switch (event) {
case undefined: {
stateName = 'undefined';
break;
}
case FilterMaintenance.FILTER_OK: {
stateName = 'FILTER OK';
break;
}
case FilterMaintenance.CHANGE_FILTER: {
stateName = 'CHANGE FILTER';
break;
}
default: {
stateName = event.toString();
}
}
return stateName;
}
onTimerExpired() {
this.filterChangeIndicator = FilterMaintenance.CHANGE_FILTER;
this.storeState();
this.log.info(`[${this.accessoryConfiguration.accessoryName}] Filter lifetime expired`);
}
}
//# sourceMappingURL=virtualAccessoryFilterMaintenance.js.map