UNPKG

shellies-ds9

Version:

Handles communication with the next generation of Shelly devices

196 lines 7.08 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ComponentWithId = exports.Component = exports.ComponentBase = exports.characteristic = void 0; const fast_deep_equal_1 = __importDefault(require("fast-deep-equal")); const eventemitter3_1 = __importDefault(require("eventemitter3")); /** * Property decorator used to label properties as characteristics. * @param target - The prototype of the component class that the property belongs to. * @param propertyName - The name of the property. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any const characteristic = (target, propertyName) => { // make sure the given prototype has an array of properties if (!Object.prototype.hasOwnProperty.call(target, '_characteristicProps')) { target._characteristicProps = new Array(); } // get the array of properties const props = target._characteristicProps; // add this property to the array props.push(propertyName); }; exports.characteristic = characteristic; /** * Base class for all device components. */ class ComponentBase extends eventemitter3_1.default { /** * @param name - The name of this component. Used when making RPCs. * @param device - The device that owns this component. * @param key - The key used to identify the component in status updates etc. If `null`, the component name * in lower case letters will be used. */ constructor(name, device, key = null) { super(); this.name = name; this.device = device; this._characteristics = null; this.key = key !== null ? key : name.toLowerCase(); } /** * A list of all characteristics. */ get characteristics() { if (this._characteristics === null) { // construct an array of properties stored by the @characteristic property decorator const props = new Array(); let proto = Object.getPrototypeOf(this); // traverse the prototype chain and collect all properties while (proto !== null) { if (Object.prototype.hasOwnProperty.call(proto, '_characteristicProps')) { props.push(...proto._characteristicProps); } proto = Object.getPrototypeOf(proto); } // store the list this._characteristics = new Set(props); } return this._characteristics; } /** * Updates the characteristics of the component. * This method will emit `change` events for all characteristics that are * updated. * @param data - A data object that contains characteristics and their values. */ update(data) { const cs = this.characteristics; const changed = new Set(); if (!cs) { // abort if we don't have any characteristics return; } // loop through each of our characteristics for (const c of cs) { if (!Object.prototype.hasOwnProperty.call(data, c)) { // ignore if this characteristic is not in the data set continue; } if (typeof data[c] === 'object' && this[c]) { // if this is an object, we need to check for deep equality if ((0, fast_deep_equal_1.default)(data[c], this[c])) { // skip if nothing has changed continue; } // copy the attributes of the characteristic Object.assign(this[c], data[c]); } else { if (data[c] === this[c]) { // skip if the value is unchanged continue; } // assign the new value to our characteristic this[c] = data[c]; } // add it to the list of changed characteristics changed.add(c); } // emit all change events after the characteristics have been updated for (const c of changed) { this.emit('change', c, this[c]); this.emit('change:' + c, this[c]); } } /** * Handles events received from the device RPC handler. * Subclasses should override this method to handle their specific events. * @param event - The event that has occurred. */ handleEvent(event) { if (event.event === 'config_changed') { this.emit('configChange', event.cfg_rev, event.restart_required); } } /** * Shorthand method for making an RPC. */ rpc(method, params) { return this.device.rpcHandler.request(`${this.name}.${method}`, params); } } exports.ComponentBase = ComponentBase; /** * Defines a set of methods common for (almost) all device components. */ class Component extends ComponentBase { /** * Retrieves the status of this component. */ getStatus() { return this.rpc('GetStatus'); } /** * Retrieves the configuration of this component. */ getConfig() { return this.rpc('GetConfig'); } /** * Requests changes in the configuration of this component. * @param config - The configuration options to set. */ setConfig(config) { return this.rpc('SetConfig', { config, }); } } exports.Component = Component; /** * Base class for components with an ID. */ class ComponentWithId extends Component { /** * @param name - The name of this component. Used when making RPCs. * @param device - The device that owns this component. * @param id - ID of this component. * @param key - The key used to identify the component in status updates etc. If `null`, the component name * in lower case letters will be used. The component ID will be appended to this key. */ constructor(name, device, id = 0, key = null) { super(name, device, (key !== null ? key : name.toLowerCase()) + ':' + id); this.id = id; } /** * Retrieves the status of this component. */ getStatus() { return this.rpc('GetStatus', { id: this.id, }); } /** * Retrieves the configuration of this component. */ getConfig() { return this.rpc('GetConfig', { id: this.id, }); } /** * Requests changes in the configuration of this component. * @param config - The configuration options to set. */ setConfig(config) { return this.rpc('SetConfig', { id: this.id, config, }); } } exports.ComponentWithId = ComponentWithId; //# sourceMappingURL=base.js.map