homey-api
Version:
183 lines (151 loc) • 4.4 kB
JavaScript
'use strict';
const Util = require('../../../Util');
const EventEmitter = require('../../../EventEmitter');
/**
* @class
* @hideconstructor
* @extends EventEmitter
* @memberof HomeyAPIV3.ManagerDevices.Device
*/
class DeviceCapability extends EventEmitter {
constructor({
id,
device,
listener,
}) {
super();
this.__onCapabilityValue = this.__onCapabilityValue.bind(this);
this.__onDeviceDelete = this.__onDeviceDelete.bind(this);
// Set ID
Object.defineProperty(this, 'id', {
value: id,
enumerable: true,
writable: false,
});
// Set Device
Object.defineProperty(this, 'device', {
value: device,
enumerable: false,
writable: false,
});
// Set Listener
Object.defineProperty(this, '__listener', {
value: listener,
enumerable: false,
writable: false,
});
// Set Listener
Object.defineProperty(this, '__transactionIds', {
value: {},
enumerable: false,
writable: false,
});
// Set Value
Object.defineProperty(this, '__value', {
value: device.capabilitiesObj
? device.capabilitiesObj[this.id]
? device.capabilitiesObj[this.id].value
: null
: null,
enumerable: false,
writable: true,
});
// Set Last Changed
Object.defineProperty(this, '__lastChanged', {
value: device.capabilitiesObj
? device.capabilitiesObj[this.id]
? device.capabilitiesObj[this.id].lastUpdated
: null
: null,
enumerable: false,
writable: true,
});
this.device.on('capability', this.__onCapabilityValue);
this.device.on('delete', this.__onDeviceDelete);
}
__debug(...props) {
this.device.__debug(`[DeviceCapability:${this.id}]`, ...props);
}
/**
* Destroy this capability listener, and if it's the last one, unsubscribe from the device's realtime events.
*/
destroy() {
this.emit('destroy');
this.device.off('capability', this.__onCapabilityValue);
this.device.off('delete', this.__onDeviceDelete);
this.removeAllListeners();
}
__onCapabilityValue({
capabilityId,
value,
transactionId,
transactionTime,
}) {
if (capabilityId !== this.id) return;
if (this.__transactionIds[transactionId]) {
delete this.__transactionIds[transactionId];
return;
}
const nextLastChanged = new Date(transactionTime);
if (this.lastChanged != null && nextLastChanged.getTime() === this.lastChanged.getTime()) {
return;
}
this.__value = value;
this.__lastChanged = nextLastChanged;
// Mutate the current device capabilitiesObj so it always reflects the last value.
const capabilityReference = this.device.capabilitiesObj && this.device.capabilitiesObj[this.id];
if (capabilityReference) {
capabilityReference.value = value;
capabilityReference.lastUpdated = this.lastChanged;
}
this.__listener(value, this);
}
__onDeviceDelete() {
this.destroy();
}
/**
* @type {boolean|number|string|null}
*/
get value() {
return typeof this.__value !== 'undefined'
? this.__value
: null;
}
/**
* @type {Date|null}
*/
get lastChanged() {
return (this.__lastChanged instanceof Date)
? this.__lastChanged
: (typeof this.__lastChanged === 'string')
? new Date(this.__lastChanged)
: null;
}
/**
* Sets a new capability value.
* @param {boolean|number|string} value - The new capability value
* @param {object} [opts]
* @param {number} [opts.duration]
*/
async setValue(value, opts) {
const transactionId = `homey-api-${Util.uuid()}`;
const transactionTime = Date.now();
this.__transactionIds[transactionId] = transactionTime;
await this.device.setCapabilityValue({
value,
opts,
transactionId,
transactionTime,
capabilityId: this.id,
});
this.__value = value;
this.__lastChanged = transactionTime;
// Mutate the current device capabilitiesObj so it always reflects the last value.
const capabilityReference = this.device.capabilitiesObj && this.device.capabilitiesObj[this.id];
if (capabilityReference) {
capabilityReference.value = value;
capabilityReference.lastUpdated = this.lastChanged;
}
}
}
module.exports = DeviceCapability;