UNPKG

homebridge-lutron-caseta-leap-fast

Version:
208 lines 9.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PicoRemote = void 0; const platform_1 = require("./platform"); const ButtonState_1 = require("./ButtonState"); const lutron_leap_1 = require("lutron-leap"); const util_1 = require("util"); // This maps DeviceType and ButtonNumber to human-readable labels and // ServiceLabelIndex values. n.b. the labels are not shown in Apple's Home app, // but are shown in other apps. The index value determines the order that // buttons are shown in the Home app. They're ordered top-to-bottom (as they // appear on the physical remote) in this map. // // [ // $DeviceType, // new Map([ // [$ButtonNumber, { label: '...', index: ... }], // ... // ]), // ] const BUTTON_MAP = new Map([ [ 'Pico2Button', new Map([ [0, { label: 'On', index: 1, isUpDown: false }], [2, { label: 'Off', index: 2, isUpDown: false }], ]), ], [ 'Pico2ButtonRaiseLower', new Map([ [0, { label: 'On', index: 1, isUpDown: false }], [2, { label: 'Off', index: 4, isUpDown: false }], [3, { label: 'Raise', index: 2, isUpDown: true }], [4, { label: 'Lower', index: 3, isUpDown: true }], ]), ], [ 'Pico3Button', new Map([ [0, { label: 'On', index: 1, isUpDown: false }], [1, { label: 'Center', index: 2, isUpDown: false }], [2, { label: 'Off', index: 3, isUpDown: false }], ]), ], [ 'Pico3ButtonRaiseLower', new Map([ [0, { label: 'On', index: 1, isUpDown: false }], [1, { label: 'Center', index: 3, isUpDown: false }], [2, { label: 'Off', index: 5, isUpDown: false }], [3, { label: 'Raise', index: 2, isUpDown: true }], [4, { label: 'Lower', index: 4, isUpDown: true }], ]), ], [ 'Pico4Button2Group', new Map([ [1, { label: 'Group 1 On', index: 1, isUpDown: false }], [2, { label: 'Group 1 Off', index: 2, isUpDown: false }], [3, { label: 'Group 2 On', index: 3, isUpDown: false }], [4, { label: 'Group 2 Off', index: 4, isUpDown: false }], ]), ], [ 'Pico4ButtonScene', new Map([ [1, { label: 'Button 1', index: 1, isUpDown: false }], [2, { label: 'Button 2', index: 2, isUpDown: false }], [3, { label: 'Button 3', index: 3, isUpDown: false }], [4, { label: 'Button 4', index: 4, isUpDown: false }], ]), ], [ 'Pico4ButtonZone', new Map([ [1, { label: 'Button 1', index: 1, isUpDown: false }], [2, { label: 'Button 2', index: 2, isUpDown: false }], [3, { label: 'Button 3', index: 3, isUpDown: false }], [4, { label: 'Button 4', index: 4, isUpDown: false }], ]), ], // TODO /* ['Pico4Button', new Map([ ])] */ ]); class PicoRemote { constructor(platform, accessory, bridge, options) { this.platform = platform; this.accessory = accessory; this.bridge = bridge; this.options = options; this.services = new Map(); this.trackers = new Map(); } async initialize() { const fullName = this.accessory.context.device.FullyQualifiedName.join(' '); this.accessory .getService(this.platform.api.hap.Service.AccessoryInformation) .setCharacteristic(this.platform.api.hap.Characteristic.Manufacturer, 'Lutron Electronics Co., Inc') .setCharacteristic(this.platform.api.hap.Characteristic.Model, this.accessory.context.device.ModelNumber) .setCharacteristic(this.platform.api.hap.Characteristic.SerialNumber, this.accessory.context.device.SerialNumber.toString()); const label_svc = this.accessory.getService(this.platform.api.hap.Service.ServiceLabel) || this.accessory.addService(this.platform.api.hap.Service.ServiceLabel); label_svc.setCharacteristic(this.platform.api.hap.Characteristic.ServiceLabelNamespace, this.platform.api.hap.Characteristic.ServiceLabelNamespace.ARABIC_NUMERALS); let bgs; try { bgs = await this.bridge.getButtonGroupsFromDevice(this.accessory.context.device); } catch (e) { this.platform.log.error('Failed to get button group(s) belonging to', fullName, e); return { kind: platform_1.DeviceWireResultType.Error, reason: `Failed to get button group(s) belonging to ${fullName}: ${e}`, }; } // if there are any buttongroups that are already associated in the // lutron app, and we've been told to skip them, return early. if (bgs.some((bg) => bg.AffectedZones !== undefined) && this.options.filterPico) { return { kind: platform_1.DeviceWireResultType.Skipped, reason: 'Associated with a device outside HomeKit', }; } bgs.forEach((bg) => { if (bg instanceof lutron_leap_1.ExceptionDetail) { return new Error('Device has been removed'); } }); let buttons = []; for (const bg of bgs) { try { buttons = buttons.concat(await this.bridge.getButtonsFromGroup(bg)); } catch (e) { this.platform.log.error('Failed to get buttons from button group', bg.href); return { kind: platform_1.DeviceWireResultType.Error, reason: `Failed to get buttons from button group ${bg.href}: ${e}`, }; } } for (const button of buttons) { const dentry = BUTTON_MAP.get(this.accessory.context.device.DeviceType); if (dentry === undefined) { return { kind: platform_1.DeviceWireResultType.Error, reason: `Could not find ${this.accessory.context.device.DeviceType} in button map`, }; } const alias = dentry.get(button.ButtonNumber); if (alias === undefined) { return { kind: platform_1.DeviceWireResultType.Error, reason: `Could not find button ${button.ButtonNumber} in ${this.accessory.context.device.DeviceType} map entry`, }; } this.platform.log.debug(`setting up ${button.href} named ${button.Name} numbered ${button.ButtonNumber} as ${(0, util_1.inspect)(alias, true, null)}`); const service = this.accessory.getServiceById(this.platform.api.hap.Service.StatelessProgrammableSwitch, alias.label) || this.accessory.addService(this.platform.api.hap.Service.StatelessProgrammableSwitch, button.Name, alias.label); service.addLinkedService(label_svc); service.setCharacteristic(this.platform.api.hap.Characteristic.Name, alias.label); service.setCharacteristic(this.platform.api.hap.Characteristic.ServiceLabelIndex, alias.index); service .getCharacteristic(this.platform.api.hap.Characteristic.ProgrammableSwitchEvent) .setProps({ maxValue: 2 }); this.services.set(button.href, service); this.trackers.set(button.href, new ButtonState_1.ButtonTracker(() => service .getCharacteristic(this.platform.api.hap.Characteristic.ProgrammableSwitchEvent) .updateValue(this.platform.api.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS), () => service .getCharacteristic(this.platform.api.hap.Characteristic.ProgrammableSwitchEvent) .updateValue(this.platform.api.hap.Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS), () => service .getCharacteristic(this.platform.api.hap.Characteristic.ProgrammableSwitchEvent) .updateValue(this.platform.api.hap.Characteristic.ProgrammableSwitchEvent.LONG_PRESS), this.platform.log, button.href, this.options.clickSpeedDouble, this.options.clickSpeedLong, alias.isUpDown)); this.platform.log.debug(`subscribing to ${button.href} events`); this.bridge.subscribeToButton(button, this.handleEvent.bind(this)); // when the connection is lost, so are subscriptions. this.bridge.on('disconnected', () => { this.platform.log.debug(`re-subscribing to ${button.href} events after connection loss`); this.bridge.subscribeToButton(button, this.handleEvent.bind(this)); }); } this.platform.on('unsolicited', this.handleUnsolicited.bind(this)); return { kind: platform_1.DeviceWireResultType.Success, name: fullName, }; } handleEvent(response) { const evt = response.Body.ButtonStatus; const fullName = this.accessory.context.device.FullyQualifiedName.join(' '); this.platform.log.info(`Button ${evt.Button.href} on Pico remote ${fullName} got action ${evt.ButtonEvent.EventType}`); this.trackers.get(evt.Button.href).update(evt.ButtonEvent.EventType); } handleUnsolicited(response) { if (response.Header.MessageBodyType === 'OneButtonStatusEvent') { const href = response.Body?.ButtonStatus.Button.href; if (this.services.has(href)) { this.platform.log.warn('got unsolicited response for known button ', href, ', handling anyway'); this.handleEvent(response); } } } } exports.PicoRemote = PicoRemote; //# sourceMappingURL=PicoRemote.js.map