UNPKG

homey-api

Version:
241 lines (204 loc) 6.41 kB
'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;