UNPKG

homebridge-virtual-accessories

Version:
375 lines 21.2 kB
/* eslint-disable brace-style */ /* eslint-disable max-len */ import { Accessory } from './accessory.js'; import { InvalidSensorValueType, SensorValueUpdateNotAllowed } from '../errors.js'; import { HumidifierType } from '../configuration/schema.js'; /** * HumidifierDehumidifier - Accessory implementation */ export class HumidifierDehumidifier extends Accessory { static ACCESSORY_TYPE_NAME = 'HumidifierDehumidifier'; static CURRENTLY_INACTIVE = 0; // Characteristic.CurrentHumidifierDehumidifierState.INACTIVE static CURRENTLY_IDLE = 1; // Characteristic.CurrentHumidifierDehumidifierState.IDLE static CURRENTLY_HUMIDIFYING = 2; // Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING static CURRENTLY_DEHUMIDIFYING = 3; // Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING static AUTOMATIC = 0; // Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER static HUMIDIFY = 1; // Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER static DEHUMIDIFY = 2; // Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER static INACTIVE = 0; // Characteristic.Active.INACTIVE static ACTIVE = 1; // Characteristic.Active.ACTIVE stateStorageKey = 'HumidifierDehumidifierActive'; targetStateStorageKey = 'HumidifierDehumidifierTargetState'; humidifierThresholdStorageKey = 'HumidifierThreshold'; dehumidifierThresholdStorageKey = 'DehumidifierThreshold'; deviceType; states = { HumidifierDehumidifierActive: HumidifierDehumidifier.INACTIVE, HumidifierDehumidifierCurrentState: HumidifierDehumidifier.CURRENTLY_INACTIVE, HumidifierDehumidifierTargetState: HumidifierDehumidifier.AUTOMATIC, HumidifierThreshold: 30, DehumidifierThreshold: 60, CurrentRelativeHumidity: 50, // This value comes from sensor, set to 50% for now }; constructor(platform, accessory, accessoryConfiguration) { super(platform, accessory, accessoryConfiguration); // First configure the device based on the accessory details this.states.HumidifierDehumidifierActive = HumidifierDehumidifier.INACTIVE; this.states.HumidifierDehumidifierCurrentState = HumidifierDehumidifier.CURRENTLY_INACTIVE; this.states.HumidifierThreshold = this.accessoryConfiguration.humidifierDehumidifier.humidifierThreshold; this.states.DehumidifierThreshold = this.accessoryConfiguration.humidifierDehumidifier.dehumidifierThreshold; this.deviceType = this.accessoryConfiguration.humidifierDehumidifier.type; if (this.deviceType === HumidifierType.Humidifier) { this.states.HumidifierDehumidifierTargetState = HumidifierDehumidifier.HUMIDIFY; } else if (this.deviceType === HumidifierType.Dehumidifier) { this.states.HumidifierDehumidifierTargetState = HumidifierDehumidifier.DEHUMIDIFY; } else { this.states.HumidifierDehumidifierTargetState = HumidifierDehumidifier.AUTOMATIC; } // If the accessory is stateful retrieve stored state if (this.accessoryConfiguration.accessoryIsStateful) { const accessoryState = this.loadAccessoryState(this.storagePath); const cachedState = accessoryState[this.stateStorageKey]; const cachedTargetState = accessoryState[this.targetStateStorageKey]; if (cachedState !== undefined) { this.states.HumidifierDehumidifierActive = cachedState; } if (cachedTargetState !== undefined) { this.states.HumidifierDehumidifierTargetState = cachedTargetState; } if (this.dehumidifies()) { const cachedDehumidifierThreshold = accessoryState[this.dehumidifierThresholdStorageKey]; if (cachedDehumidifierThreshold !== undefined) { this.states.DehumidifierThreshold = cachedDehumidifierThreshold; } } if (this.humidifies()) { const cachedHumidifierThreshold = accessoryState[this.humidifierThresholdStorageKey]; if (cachedHumidifierThreshold !== undefined) { this.states.HumidifierThreshold = cachedHumidifierThreshold; } } } this.setDeviceOperationalCondition(); // get the HumidifierDehumidifier service if it exists, otherwise create a new LightBulb service this.service = this.accessory.getService(this.platform.Service.HumidifierDehumidifier) || this.accessory.addService(this.platform.Service.HumidifierDehumidifier); // These characteristics will be added back as needed this.service.removeCharacteristic(this.service.getCharacteristic(this.platform.Characteristic.RelativeHumidityDehumidifierThreshold)); this.service.removeCharacteristic(this.service.getCharacteristic(this.platform.Characteristic.RelativeHumidityHumidifierThreshold)); this.setHumidifierDehumidifierServiceProperties(this.service); // set the service name, this is what is displayed as the default name on the Home app this.service.setCharacteristic(this.platform.Characteristic.Name, this.accessoryConfiguration.accessoryName); // Update the initial state of the accessory this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Setting Humidifier/Dehumidifier Current State: ${HumidifierDehumidifier.getCurrentStateName(this.states.HumidifierDehumidifierCurrentState)}`); this.service.updateCharacteristic(this.platform.Characteristic.CurrentHumidifierDehumidifierState, (this.states.HumidifierDehumidifierCurrentState)); this.service.updateCharacteristic(this.platform.Characteristic.TargetHumidifierDehumidifierState, (this.states.HumidifierDehumidifierTargetState)); // register handlers this.service.getCharacteristic(this.platform.Characteristic.Active) .onSet(this.setActive.bind(this)) .onGet(this.getActive.bind(this)); this.service.getCharacteristic(this.platform.Characteristic.CurrentHumidifierDehumidifierState) .onGet(this.getCurrentHumidifierDehumidifierState.bind(this)); this.service.getCharacteristic(this.platform.Characteristic.TargetHumidifierDehumidifierState) .onSet(this.setTargetHumidifierDehumidifierState.bind(this)) .onGet(this.getTargetHumidifierDehumidifierState.bind(this)); this.service.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity) .onGet(this.getCurrentRelativeHumidity.bind(this)); if (this.dehumidifies()) { // Characteristic was removed when adding the Service this.service.addCharacteristic(this.platform.Characteristic.RelativeHumidityDehumidifierThreshold) .onSet(this.setRelativeHumidityDehumidifierThreshold.bind(this)) .onGet(this.getRelativeHumidityDehumidifierThreshold.bind(this)); } if (this.humidifies()) { // Characteristic was removed when adding the Service this.service.addCharacteristic(this.platform.Characteristic.RelativeHumidityHumidifierThreshold) .onSet(this.setRelativeHumidityHumidifierThreshold.bind(this)) .onGet(this.getRelativeHumidityHumidifierThreshold.bind(this)); } const characteristics = this.service.characteristics.map(characteristic => characteristic.displayName); this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Characteristics: ${characteristics.join(', ')}`); } // Handlers async setActive(value) { this.states.HumidifierDehumidifierActive = value; this.setDeviceOperationalCondition(); this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Active: ${HumidifierDehumidifier.getActiveName(this.states.HumidifierDehumidifierActive)}`); } async getActive() { const humidifierDehumidifierActive = this.states.HumidifierDehumidifierActive; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Active: ${HumidifierDehumidifier.getActiveName(humidifierDehumidifierActive)}`); return humidifierDehumidifierActive; } async getCurrentHumidifierDehumidifierState() { const humidifierDehumidifierCurrentState = this.states.HumidifierDehumidifierCurrentState; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Current Humidifier Dehumidifier State: ${HumidifierDehumidifier.getCurrentStateName(humidifierDehumidifierCurrentState)}`); return humidifierDehumidifierCurrentState; } async setTargetHumidifierDehumidifierState(value) { this.states.HumidifierDehumidifierTargetState = value; this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Target Humidifier Dehumidifier State: ${HumidifierDehumidifier.getTargetStateName(this.states.HumidifierDehumidifierTargetState)}`); this.setDeviceOperationalCondition(); this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Current Humidifier Dehumidifier State: ${HumidifierDehumidifier.getCurrentStateName(this.states.HumidifierDehumidifierCurrentState)}`); } async getTargetHumidifierDehumidifierState() { const humidifierDehumidifierTargetState = this.states.HumidifierDehumidifierTargetState; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Target Humidifier Dehumidifier State: ${HumidifierDehumidifier.getTargetStateName(humidifierDehumidifierTargetState)}`); return humidifierDehumidifierTargetState; } async getCurrentRelativeHumidity() { const currentRelativeHumidity = this.states.CurrentRelativeHumidity; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Current Relative Humidity: ${currentRelativeHumidity}%`); return currentRelativeHumidity; } async setRelativeHumidityDehumidifierThreshold(value) { this.states.DehumidifierThreshold = value; this.setDeviceOperationalCondition(); this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Relative Humidity Dehumidifier Threshold: ${this.states.DehumidifierThreshold}%`); } async getRelativeHumidityDehumidifierThreshold() { const dehumidifierThreshold = this.states.DehumidifierThreshold; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Relative Humidity Dehumidifier Threshold: ${dehumidifierThreshold}%`); return dehumidifierThreshold; } async setRelativeHumidityHumidifierThreshold(value) { this.states.HumidifierThreshold = value; this.setDeviceOperationalCondition(); this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Relative Humidity Humidifier Threshold: ${this.states.HumidifierThreshold}%`); } async getRelativeHumidityHumidifierThreshold() { const humidifierThreshold = this.states.HumidifierThreshold; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Relative Humidity Humidifier Threshold: ${humidifierThreshold}%`); return humidifierThreshold; } getJsonState() { const json = JSON.stringify({ [this.stateStorageKey]: this.states.HumidifierDehumidifierActive, [this.targetStateStorageKey]: this.states.HumidifierDehumidifierTargetState, [this.dehumidifierThresholdStorageKey]: this.states.DehumidifierThreshold, [this.humidifierThresholdStorageKey]: this.states.HumidifierThreshold, }); return json; } getAccessoryTypeName() { return HumidifierDehumidifier.ACCESSORY_TYPE_NAME; } humidifies() { return [HumidifierType.Auto, HumidifierType.Humidifier].includes(this.deviceType); } dehumidifies() { return [HumidifierType.Auto, HumidifierType.Dehumidifier].includes(this.deviceType); } setDeviceOperationalCondition() { if (this.states.HumidifierDehumidifierActive === HumidifierDehumidifier.INACTIVE) { this.states.HumidifierDehumidifierCurrentState = HumidifierDehumidifier.CURRENTLY_INACTIVE; } else { // (this.states.HumidifierDehumidifierActive === HumidifierDehumidifier.ACTIVE) if (this.states.HumidifierDehumidifierTargetState === HumidifierDehumidifier.HUMIDIFY) { this.states.HumidifierDehumidifierCurrentState = HumidifierDehumidifier.CURRENTLY_HUMIDIFYING; } else if (this.states.HumidifierDehumidifierTargetState === HumidifierDehumidifier.DEHUMIDIFY) { this.states.HumidifierDehumidifierCurrentState = HumidifierDehumidifier.CURRENTLY_DEHUMIDIFYING; } else { // (this.states.HumidifierDehumidifierTargetState === HumidifierDehumidifier.AUTOMATIC) if (this.states.CurrentRelativeHumidity < this.states.HumidifierThreshold) { if (this.humidifies()) { this.states.HumidifierDehumidifierCurrentState = HumidifierDehumidifier.CURRENTLY_HUMIDIFYING; } } else if (this.states.CurrentRelativeHumidity > this.states.DehumidifierThreshold) { if (this.dehumidifies()) { this.states.HumidifierDehumidifierCurrentState = HumidifierDehumidifier.CURRENTLY_DEHUMIDIFYING; } } else { this.states.HumidifierDehumidifierCurrentState = HumidifierDehumidifier.CURRENTLY_IDLE; } } } this.service?.setCharacteristic(this.platform.Characteristic.CurrentHumidifierDehumidifierState, (this.states.HumidifierDehumidifierCurrentState)); this.storeState(); this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Humidifier/Dehumidifier current state: ${HumidifierDehumidifier.getCurrentStateName(this.states.HumidifierDehumidifierCurrentState)}`); } static getActiveName(status) { let activeName; switch (status) { case undefined: { activeName = 'undefined'; break; } case HumidifierDehumidifier.INACTIVE: { activeName = 'INACTIVE'; break; } case HumidifierDehumidifier.ACTIVE: { activeName = 'ACTIVE'; break; } default: { activeName = status.toString(); } } return activeName; } static getCurrentStateName(state) { let stateName; switch (state) { case undefined: { stateName = 'undefined'; break; } case HumidifierDehumidifier.CURRENTLY_INACTIVE: { stateName = 'INACTIVE'; break; } case HumidifierDehumidifier.CURRENTLY_IDLE: { stateName = 'IDLE'; break; } case HumidifierDehumidifier.CURRENTLY_HUMIDIFYING: { stateName = 'HUMIDIFYING'; break; } case HumidifierDehumidifier.CURRENTLY_DEHUMIDIFYING: { stateName = 'DEHUMIDIFYING'; break; } default: { stateName = state.toString(); } } return stateName; } static getTargetStateName(state) { let stateName; switch (state) { case undefined: { stateName = 'undefined'; break; } case HumidifierDehumidifier.AUTOMATIC: { stateName = 'AUTO'; break; } case HumidifierDehumidifier.HUMIDIFY: { stateName = 'HUMIDIFY'; break; } case HumidifierDehumidifier.DEHUMIDIFY: { stateName = 'DEHUMIDIFY'; break; } default: { stateName = state.toString(); } } return stateName; } /** * Ensure all the property values are set, then remove as required */ setHumidifierDehumidifierServiceProperties(service) { const CurrentHumidifierDehumidifierState = this.platform.Characteristic.CurrentHumidifierDehumidifierState; const TargetHumidifierDehumidifierState = this.platform.Characteristic.TargetHumidifierDehumidifierState; const currentStateValues = new Set([ CurrentHumidifierDehumidifierState.INACTIVE, CurrentHumidifierDehumidifierState.IDLE, CurrentHumidifierDehumidifierState.HUMIDIFYING, CurrentHumidifierDehumidifierState.DEHUMIDIFYING, ]); const targetStateValues = new Set([ TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER, TargetHumidifierDehumidifierState.HUMIDIFIER, TargetHumidifierDehumidifierState.DEHUMIDIFIER, ]); // HUMIDIFIER: On/off humidifier // DEHUMIDIFIER: On/off dehumidifier // HUMIDIFIER_OR_DEHUMIDIFIER: Uses threshold values to humidify/dehumidify -> AUTO if (this.deviceType === HumidifierType.Humidifier) { currentStateValues.delete(CurrentHumidifierDehumidifierState.DEHUMIDIFYING); targetStateValues.delete(TargetHumidifierDehumidifierState.DEHUMIDIFIER); // Remove this only if we want manual operation only // targetStateValues.delete(TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER); this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Is a Humidifier`); } else if (this.deviceType === HumidifierType.Dehumidifier) { currentStateValues.delete(CurrentHumidifierDehumidifierState.HUMIDIFYING); targetStateValues.delete(TargetHumidifierDehumidifierState.HUMIDIFIER); // Remove this only if we want manual operation only // targetStateValues.delete(TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER); this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Is a Dehumidifier`); } else { this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Is a Humidifier/Dehumidifier`); } if (currentStateValues.size > 0) { this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Setting Current State values: ${this.getCurrentStateLabels(currentStateValues)}`); service.getCharacteristic(CurrentHumidifierDehumidifierState) .setProps({ validValues: Array.from(currentStateValues), }); this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Current State Props: ${JSON.stringify(service.getCharacteristic(CurrentHumidifierDehumidifierState).props)}`); } if (targetStateValues.size > 0) { this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Setting Target State values: ${this.getTargetStateLabels(targetStateValues)}`); service.getCharacteristic(TargetHumidifierDehumidifierState) .setProps({ validValues: Array.from(targetStateValues), }); this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Target State Props: ${JSON.stringify(service.getCharacteristic(TargetHumidifierDehumidifierState).props)}`); } } getCurrentStateLabels(values) { const labels = []; values.forEach(value => { labels.push(HumidifierDehumidifier.getCurrentStateName(value)); }); return labels; } getTargetStateLabels(values) { const labels = []; values.forEach(value => { labels.push(HumidifierDehumidifier.getTargetStateName(value)); }); return labels; } // Updatable Sensor interface updateMeasurementSensor(value, accessoryId) { this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Request update humidity sensor to ${value}%`); if (accessoryId !== this.accessoryConfiguration.accessoryID) { this.log.error(`[${this.accessoryConfiguration.accessoryName}] Accessory Id ${accessoryId} is not valid for this accessory`); throw new SensorValueUpdateNotAllowed(`Invalid accessory id: ${accessoryId}`); } else if (typeof value !== 'number') { this.log.error(`[${this.accessoryConfiguration.accessoryName}] Value ${value} is not valid for Humidifier/Dehumidifier sensor`); throw new InvalidSensorValueType(`Invalid sensor value: ${value}`); } else { this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Updating humidity sensor to ${value}%`); this.states.CurrentRelativeHumidity = value; this.setDeviceOperationalCondition(); } } } //# sourceMappingURL=virtualAccessoryHumidifierDehumidifier.js.map