homey-api
Version:
241 lines (204 loc) • 6.41 kB
JavaScript
'use strict';
const Util = require('../../../Util');
const Item = require('../Item');
const DeviceCapability = require('./DeviceCapability');
/**
* @class
* @hideconstructor
* @extends HomeyAPIV3.Item
* @memberof HomeyAPIV3.ManagerDevices
*/
class Device extends Item {
constructor(...props) {
super(...props);
// Set Capability Instances
Object.defineProperty(this, '__capabilityInstances', {
value: {},
enumerable: false,
writable: true,
});
}
/**
* Creates an {@link HomeyAPIV3.DeviceCapability} for realtime capability updates.
* @param {string} capabilityId
* @param {Function} listener
* @param {number|boolean|string} listener.value
* @returns {HomeyAPIV3.ManagerDevices.Device.DeviceCapability}
* @function HomeyAPIV3.ManagerDevices.Device#makeCapabilityInstance
* @example
*
* const onOffInstance = device.makeCapabilityInstance('onoff', value => {
* console.log('Device onoff changed to:', value);
* });
*
* // Turn on
* onOffInstance.setValue(true).catch(console.error);
*/
makeCapabilityInstance(capabilityId, listener) {
this.__debug('Creating capability instance for: ', capabilityId);
this.connect().catch(err => {
this.__debug(err);
});
const instance = new DeviceCapability({
listener,
id: capabilityId,
device: this,
});
instance.once('destroy', () => {
this.__capabilityInstances[capabilityId] = this.__capabilityInstances[capabilityId] || [];
this.__capabilityInstances[capabilityId] = this.__capabilityInstances[capabilityId].filter(i => i !== instance);
if (this.__capabilityInstances[capabilityId].length === 0) {
delete this.__capabilityInstances[capabilityId];
}
if (Object.keys(this.__capabilityInstances).length === 0) {
this.__debug('No more Capability instances, disconnecting...');
this.disconnect().catch(err => this.__debug(err));
}
});
this.__capabilityInstances[capabilityId] = this.__capabilityInstances[capabilityId] || [];
this.__capabilityInstances[capabilityId].push(instance);
// Schedule a refresh if it's been more than a second since the device has updated.
const now = Date.now();
if (this.__lastUpdated.getTime() + 2500 < now) {
this.manager.scheduleRefresh();
}
return instance;
}
/**
* Sets a capability's value.
* @param {object} opts
* @param {string} opts.capabilityId
* @param {number|boolean|string} opts.value
* @param {object} [opts.opts]
* @param {number} [opts.opts.duration]
* @returns {Promise<void>}
* @function HomeyAPIV3.ManagerDevices.Device#setCapabilityValue
*/
async setCapabilityValue(options, ...args) {
// Legacy compatibility from node-athom-api
if (typeof options === 'string') {
return this.setCapabilityValueLegacy(options, ...args);
}
return this.__setCapabilityValue(options);
}
async __setCapabilityValue({
capabilityId,
value,
opts,
transactionId = `homey-api-${Util.uuid()}`,
transactionTime = Date.now(),
}) {
return this.manager.setCapabilityValue({
deviceId: this.id,
capabilityId,
value,
opts,
transactionId,
transactionTime,
});
}
async setCapabilityValueLegacy(capabilityId, value, opts) {
return this.__setCapabilityValue({
capabilityId,
value,
opts,
});
}
onReconnect() {
this.manager.scheduleRefresh();
}
/**
* Get the device's zone.
* @returns {Promise<HomeyAPIV3.ManagerZones.Zone>}
*/
async getZone() {
return this.homey.zones.getZone({
id: this.zone,
});
}
/**
* Get the device's driver.
* @returns {Promise<HomeyAPIV3.ManagerDrivers.Driver>}
*/
async getDriver() {
return this.homey.drivers.getDriver({
id: this.driverId,
});
}
/**
* Get the device's logs.
* @returns {Promise.<Object.<string, HomeyAPIV3.ManagerInsights.Log>>}
*/
async getLogs() {
const logs = await this.homey.insights.getLogs();
return Object.values(logs)
.filter(log => log.ownerUri === this.uri)
.reduce((accumulator, log) => {
accumulator[log.id] = log;
return accumulator;
}, {});
}
/**
* Get the device's flows.
* @returns {Promise.<Object.<string, HomeyAPIV3.ManagerFlow.Flow>>}
*/
async getFlows() {
const flows = await this.homey.flow.getFlows();
return Object.values(flows)
.filter(flow => {
if (flow.trigger && flow.trigger.id.startsWith(this.uri)) return true;
if (Array.isArray(flow.conditions) && flow.conditions.some(card => card.id.startsWith(this.uri))) return true;
if (Array.isArray(flow.actions) && flow.actions.some(card => card.id.startsWith(this.uri))) return true;
// TODO: Zone cards
// TODO: Subzone cards
return false;
})
.reduce((result, flow) => ({
...result,
[flow.id]: flow,
}), {});
}
/**
* @returns {Promise.<Object.<string, HomeyAPIV3.ManagerFlow.AdvancedFlow>>}
*/
async getAdvancedFlows() {
const advancedFlows = await this.homey.flow.getAdvancedFlows();
return Object.values(advancedFlows)
.filter(advancedFlow => {
return Object.values(advancedFlow.cards)
.filter(card => ['trigger', 'condition', 'action'].includes(card.type))
.some(card => {
if (card.id.startsWith(this.uri)) return true;
// TODO: Zone cards
// TODO: Subzone cards
return false;
});
})
.reduce((result, advancedFlow) => ({
...result,
[advancedFlow.id]: advancedFlow,
}), {});
}
static transformGet(item) {
item = super.transformGet(item);
delete item.driverUri;
delete item.insights;
if (item.capabilitiesObj) {
for (const capabilityObj of Object.values(item.capabilitiesObj)) {
if (capabilityObj.lastUpdated) {
capabilityObj.lastUpdated = new Date(capabilityObj.lastUpdated);
}
}
}
return item;
}
get driverUri() {
console.warn('Device.driverUri is deprecated. Please use Device.driverId instead.');
return undefined;
}
get zoneName() {
console.warn('Device.zoneName is deprecated.');
return undefined;
}
}
module.exports = Device;