homebridge-virtual-accessories
Version:
Virtual HomeKit accessories for Homebridge.
215 lines • 9.4 kB
JavaScript
import { Accessory } from './accessory.js';
import { Timer } from '../utils/timer.js';
/**
* Valve - Accessory implementation
*/
export class Valve extends Accessory {
static ACCESSORY_TYPE_NAME = 'Valve';
static GENERIC_VALVE = 0; // Characteristic.ValveType.GENERIC_VALVE
static IRRIGATION = 1; // Characteristic.ValveType.IRRIGATION
static SHOWER_HEAD = 2; // Characteristic.ValveType.SHOWER_HEAD
static WATER_FAUCET = 3; // Characteristic.ValveType.WATER_FAUCET
static INACTIVE = 0; // Characteristic.Active.INACTIVE
static ACTIVE = 1; // Characteristic.Active.ACTIVE
static NOT_IN_USE = 0; // Characteristic.InUse.NOT_IN_USE
static IN_USE = 1; // Characteristic.InUse.IN_USE
valveType;
durationTimer;
stateStorageKey = 'ValveActive';
// private readonly timerStartTimeStorageKey: string = 'TimerStartTime';
// private readonly timerDurationStorageKey: string = 'TimerDuration';
// private readonly timerIsRunningStorageKey: string = 'TimerIsRunning';
states = {
ValveActive: Valve.INACTIVE,
ValveInUse: Valve.NOT_IN_USE,
};
constructor(platform, accessory, accessoryConfiguration) {
super(platform, accessory, accessoryConfiguration);
switch (this.accessoryConfiguration.valve.type) {
case 'generic':
this.valveType = Valve.GENERIC_VALVE;
break;
case 'irrigation':
this.valveType = Valve.IRRIGATION;
break;
case 'showerhead':
this.valveType = Valve.SHOWER_HEAD;
break;
case 'waterfaucet':
this.valveType = Valve.WATER_FAUCET;
break;
// Should never drop down to here, but being defensive
default:
this.valveType = Valve.GENERIC_VALVE;
break;
}
// First configure the device based on the accessory details
this.states.ValveActive = Valve.INACTIVE;
this.states.ValveInUse = Valve.NOT_IN_USE;
// If the accessory is stateful retrieve stored state
if (this.accessoryConfiguration.accessoryIsStateful) {
const accessoryState = this.loadAccessoryState(this.storagePath);
const cachedState = accessoryState[this.stateStorageKey];
if (cachedState !== undefined) {
this.states.ValveActive = cachedState;
this.states.ValveInUse = (this.states.ValveActive === Valve.ACTIVE) ? Valve.IN_USE : Valve.NOT_IN_USE;
}
}
// Timer is not resettable
const timerIsResettable = false;
this.durationTimer = new Timer(this.accessoryConfiguration.accessoryName, this.log, timerIsResettable, this.accessoryConfiguration.valve.duration.toSeconds());
this.service = this.accessory.getService(this.platform.Service.Valve) || this.accessory.addService(this.platform.Service.Valve);
this.service.setCharacteristic(this.platform.Characteristic.Name, this.accessoryConfiguration.accessoryName);
// Update the initial state of the accessory
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Setting Valve Current State: ${Valve.getActiveName(this.states.ValveActive)}`);
this.service.updateCharacteristic(this.platform.Characteristic.Active, (this.states.ValveActive));
this.service.updateCharacteristic(this.platform.Characteristic.InUse, (this.states.ValveInUse));
this.service.updateCharacteristic(this.platform.Characteristic.SetDuration, (this.accessoryConfiguration.valve.duration.toSeconds()));
// register handlers
this.service.getCharacteristic(this.platform.Characteristic.ValveType)
.onGet(this.getValveType.bind(this));
this.service.getCharacteristic(this.platform.Characteristic.Active)
.onSet(this.setActive.bind(this))
.onGet(this.getActive.bind(this));
this.service.getCharacteristic(this.platform.Characteristic.InUse)
.onGet(this.getInUse.bind(this));
this.service.getCharacteristic(this.platform.Characteristic.SetDuration)
.onSet(this.setSetDuration.bind(this))
.onGet(this.getSetDuration.bind(this));
this.service.getCharacteristic(this.platform.Characteristic.RemainingDuration)
.onGet(this.getRemainingDuration.bind(this));
}
// Handlers
async getValveType() {
const valveType = this.valveType;
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Valve Type: ${Valve.getValveTypeName(valveType)}`);
return valveType;
}
async setActive(value) {
this.states.ValveActive = value;
this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Active: ${Valve.getActiveName(this.states.ValveActive)}`);
this.states.ValveInUse = (this.states.ValveActive === Valve.ACTIVE) ? Valve.IN_USE : Valve.NOT_IN_USE;
this.service.setCharacteristic(this.platform.Characteristic.InUse, (this.states.ValveInUse));
this.storeState();
this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting In Use: ${Valve.getInUseName(this.states.ValveInUse)}`);
// Valve was turned off: turn off timer
if (this.states.ValveActive === Valve.INACTIVE) {
this.durationTimer.stop();
}
// Valve was turned on: try to start timer
if (this.states.ValveActive === Valve.ACTIVE && this.accessoryConfiguration.valve.duration.toSeconds() > 0) {
this.durationTimer.start(() => {
this.service.setCharacteristic(this.platform.Characteristic.Active, Valve.INACTIVE);
});
}
}
async getActive() {
const valveActive = this.states.ValveActive;
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Active: ${Valve.getActiveName(valveActive)}`);
return valveActive;
}
async getInUse() {
const valveInUse = this.states.ValveInUse;
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting In Use: ${Valve.getInUseName(valveInUse)}`);
return valveInUse;
}
async setSetDuration(value) {
const duration = value;
this.durationTimer.setDefaultDuration(duration);
this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Set Duration: ${duration} seconds`);
}
async getSetDuration() {
const duration = this.durationTimer.getDefaultDuration();
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Set Duration: ${duration} seconds`);
return duration;
}
async getRemainingDuration() {
const remainingDuration = this.durationTimer.getRemainingDuration();
this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Remaining Duration: ${remainingDuration} seconds`);
return remainingDuration;
}
getJsonState() {
const json = JSON.stringify({
[this.stateStorageKey]: this.states.ValveActive,
// [this.timerStartTimeStorageKey]: this.durationTimer.getStartTime().toString(),
// [this.timerDurationStorageKey]: this.durationTimer.getDuration(),
// [this.timerIsRunningStorageKey]: this.durationTimer.isTimerRunning(),
});
return json;
}
getAccessoryTypeName() {
return Valve.ACCESSORY_TYPE_NAME;
}
static getValveTypeName(event) {
let eventName;
switch (event) {
case undefined: {
eventName = 'undefined';
break;
}
case Valve.GENERIC_VALVE: {
eventName = 'GENERIC VALVE';
break;
}
case Valve.IRRIGATION: {
eventName = 'IRRIGATION';
break;
}
case Valve.SHOWER_HEAD: {
eventName = 'SHOWER HEAD';
break;
}
case Valve.WATER_FAUCET: {
eventName = 'WATER FAUCET';
break;
}
default: {
eventName = event.toString();
}
}
return eventName;
}
static getActiveName(event) {
let eventName;
switch (event) {
case undefined: {
eventName = 'undefined';
break;
}
case Valve.INACTIVE: {
eventName = 'INACTIVE';
break;
}
case Valve.ACTIVE: {
eventName = 'ACTIVE';
break;
}
default: {
eventName = event.toString();
}
}
return eventName;
}
static getInUseName(event) {
let eventName;
switch (event) {
case undefined: {
eventName = 'undefined';
break;
}
case Valve.NOT_IN_USE: {
eventName = 'NOT IN USE';
break;
}
case Valve.IN_USE: {
eventName = 'IN USE';
break;
}
default: {
eventName = event.toString();
}
}
return eventName;
}
}
//# sourceMappingURL=virtualAccessoryValve.js.map