UNPKG

homebridge-philips-hue-sync-box-switches

Version:

Homebridge plugin for the Philips Hue Sync Box. Adapted to be Switch accessories.

441 lines (392 loc) 17.3 kB
/** * Represents a physical Sync Boxthis. * @param platform The PhilipsHueSyncBoxPlatform instance. * @param state The state. */ export class SyncBoxDevice { getLastSyncMode = () => { if (this.state && this.state.execution && this.state.execution.lastSyncMode) { return this.state.execution.lastSyncMode; } return 'video' } getName = (suffix) => { return [this.platform.config.syncBoxNameOverride || this.state.device.name, suffix].join(' ') } isOn = (check) => { if (this.state && this.state.execution && this.state.execution.mode) { if (!!check) { return this.state.execution.mode == check } return this.state.execution.mode !== 'powersave' && this.state.execution.mode !== 'passthrough' } return false }; isInput = (input) => { return this.state && this.state.execution && this.state.execution.hdmiSource == input } isIntensity = (intensity) => { if (this.state.execution.mode == 'powersave' || this.state.execution.mode == 'passthrough') { return false; } let mode = this.getLastSyncMode() let currentIntensity = this.state.execution[mode].intensity switch (true) { case intensity == 'subtle': case intensity == 'moderate': case intensity == 'high': case intensity == 'intense': return currentIntensity == intensity; default: this.platform.log(`unknown intensity '${intensity}'`); return false; } } /** Only call in constructor before switches! */ addAccessory = (name) => { const { UUIDGen, Accessory } = this.platform; // Gets the main light bulb accessory let accessory = this.unusedDeviceAccessories.find(function (a) { return a.context.kind === name; }); if (accessory) { this.unusedDeviceAccessories.splice(this.unusedDeviceAccessories.indexOf(accessory), 1); } else { this.platform.log(`Adding new accessory '${name}'.`); accessory = new Accessory(this.getName(name), UUIDGen.generate(name)); accessory.context.kind = name; this.newDeviceAccessories.push(accessory); } this.deviceAccessories.push(accessory); return accessory } getBrightness = () => { if (this.state && this.state.execution) { return this.state.execution.brightness / 2; } return 0; } removeBrightness = (accessory, name) => { const { Service } = this.platform; // Removes the light bulb service let service = accessory.getService(name); if (service) { accessory.removeService(service); } } setUpBrightness = (accessory, name) => { const { Characteristic, Service } = this.platform; // Updates the light bulb service let service = accessory.getService(name); if (!service) { service = accessory.addService(Service.Lightbulb, name); } service.getCharacteristic(Characteristic.On) .onGet(() => this.isOn(null)); service.getCharacteristic(Characteristic.Brightness) .onGet(() => this.getBrightness()); service.getCharacteristic(Characteristic.On) .on('set', (value, callback) => { // Saves the changes if (value) { this.platform.log.debug('Switch state to lastSyncMode'); this.platform.limiter.schedule(() => { return this.platform.client.updateExecution({ 'mode': this.getLastSyncMode() }); }) .then(() => {}, () => { this.platform.log('Failed to switch state to ON'); }); } else { this.platform.log.debug('Switch state to OFF'); this.platform.limiter.schedule(() => { return this.platform.client.updateExecution({ 'mode': this.platform.config.defaultOffMode }); }) .then(() => {}, () => { this.platform.log('Failed to switch state to OFF'); }); } // Performs the callback callback(null); }); service.getCharacteristic(Characteristic.Brightness) .on('set', (value, callback) => { // Saves the changes if (value) { this.platform.limiter.schedule(() => { return this.platform.client.updateExecution({ 'brightness': Math.round((value / 100.0) * 200) }); }) .then(() => {}, () => { this.platform.log('Failed to set brightness'); }); } // Performs the callback callback(null); }); this.onUpdate(() => { service.getCharacteristic(Characteristic.On) .updateValue(this.isOn(null)); service.getCharacteristic(Characteristic.Brightness) .updateValue(this.getBrightness()); }) } setUpModeSwitch = (accessory, name, mode) => { const { Characteristic, Service } = this.platform; // Updates the light bulb service let service = accessory.getService(name); if (!service) { service = accessory.addService(Service.Switch, name, mode); } service.getCharacteristic(Characteristic.On) .onGet(() => this.isOn(mode)); service.getCharacteristic(Characteristic.On) .on('set', (value, callback) => { // Saves the changes if (value) { this.platform.log.debug('Switch state to lastSyncMode'); this.platform.limiter.schedule(() => { return this.platform.client.updateExecution({ 'mode': mode || this.getLastSyncMode() }); }) .then(() => {}, () => { this.platform.log('Failed to switch state to ON'); }); } else { this.platform.log.debug('Switch state to OFF'); this.platform.limiter.schedule(() => { return this.platform.client.updateExecution({ 'mode': this.platform.config.defaultOffMode }); }) .then(() => {}, () => { this.platform.log('Failed to switch state to OFF'); }); } // Performs the callback callback(null); }); this.onUpdate(() => { service.getCharacteristic(Characteristic.On) .updateValue(this.isOn(mode)); }) } setUpIntensitySwitch = (accessory, name, intensity) => { const { Characteristic, Service } = this.platform; let service = accessory.getService(name); if (!service) { service = accessory.addService(Service.Switch, name, intensity); } service.getCharacteristic(Characteristic.On) .onGet(() => this.isIntensity(intensity)); service.getCharacteristic(Characteristic.On) .on('set', (value, callback) => { // Saves the changes if (value) { this.platform.log.debug(`Switch intensity to ${intensity}`); this.platform.limiter.schedule(() => { return this.platform.client.updateExecution({ 'intensity': intensity }); }) .then(() => { callback(null); }, () => { this.platform.log('Failed to switch state to ON'); callback('Failed to switch state to ON'); }); } else { // this can only turn on. // service.getCharacteristic(Characteristic.On).updateValue(true) callback(`cannot be turned off by user`); } }); this.onUpdate(() => { service.getCharacteristic(Characteristic.On) .updateValue(this.isIntensity(intensity)); }) } /** accessory: HMAccessory name: String handle to reference the switch in HomeKit inputName: String handle to reference the input on the Hue Bridge (input<n>) */ setUpInputSwitch = (accessory, name, inputName) => { const { Characteristic, Service } = this.platform; // Updates the light bulb service let service = accessory.getService(name); if (!service) { service = accessory.addService(Service.Switch, name, inputName); } service.getCharacteristic(Characteristic.On) .onGet(() => this.isInput(inputName)); service.getCharacteristic(Characteristic.On) .on('set', (value, callback) => { // Saves the changes if (value) { this.platform.log.debug(`Switch input to ${inputName}`); this.platform.limiter.schedule(() => { return this.platform.client.updateExecution({ 'hdmiSource': inputName }); }) .then(() => { callback(null); }, () => { this.platform.log(`Failed to switch input ${index} to ON`); callback('Failed to switch state to ON'); }); } else { // this can only turn on. // service.getCharacteristic(Characteristic.On).updateValue(true) callback(`cannot be turned off by user`); } /* else { this.platform.log.debug('Switch state to OFF'); this.platform.limiter.schedule(() => { return this.platform.client.updateExecution({ 'mode': this.platform.config.defaultOffMode }); }).then(() => {}, () => { this.platform.log('Failed to switch state to OFF'); }); }*/ // Performs the callback }); this.onUpdate(() => { service.getCharacteristic(Characteristic.On) .updateValue(this.isInput(inputName)); }) } updateCallbacks = []; onUpdate = (callback) => { this.updateCallbacks.push(callback); } constructor(platform, state) { const { UUIDGen, Accessory, Characteristic, Service, Categories } = platform; // Sets the platform this.platform = platform; // Stores the latest state this.state = state; this.platform.client.stateUpdate = (new_state) => { this.state = new_state; for (let cb of this.updateCallbacks) { cb(); } } // Gets all accessories from the platform this.externalAccessories = []; this.unusedDeviceAccessories = platform.accessories.slice(); this.newDeviceAccessories = []; this.deviceAccessories = []; let brightnessState, powerState, modeState, intensityState, inputState = null switch (true) { case platform.config.hideBrightness && platform.config.unifiedAccessory: platform.log(`unifiedAccessory is enabled. Only registering 1 accessory`); powerState = this.addAccessory(this.platform.config.syncBoxNameOverride || this.state.device.name); modeState = powerState; intensityState = powerState; inputState = powerState; break; case platform.config.unifiedAccessory: platform.log(`unifiedAccessory is enabled. Only registering 1 accessory`); brightnessState = this.addAccessory(this.platform.config.syncBoxNameOverride || this.state.device.name); powerState = brightnessState; modeState = brightnessState; intensityState = brightnessState; inputState = brightnessState; break; case platform.config.hideBrightness: platform.log(`hideBrightness is enabled. Skipping Lightbulb accessory`) platform.log(`unifiedAccessory is disabled. Registering all accessories`); powerState = this.addAccessory("Power"); modeState = this.addAccessory("Mode"); intensityState = this.addAccessory("Intensity"); inputState = this.addAccessory("Input"); break; default: platform.log(`hideBrightness is disabled. Registering Lightbulb accessory`) platform.log(`unifiedAccessory is disabled. Registering all accessories`); brightnessState = this.addAccessory("Brightness"); powerState = this.addAccessory("Power"); modeState = this.addAccessory("Mode"); intensityState = this.addAccessory("Intensity"); inputState = this.addAccessory("Input"); break; } if (!powerState || !modeState || !intensityState || !inputState || (!platform.config.hideBrightness && !brightnessState)) { throw ("Something broke :/") } // Registers the newly created accessories platform.api.registerPlatformAccessories(platform.pluginName, platform.platformName, this.newDeviceAccessories); // Removes all unused accessories for (let i = 0; i < this.unusedDeviceAccessories.length; i++) { const unusedDeviceAccessory = this.unusedDeviceAccessories[i]; platform.log('Removing unused accessory with kind ' + unusedDeviceAccessory.context.kind + '.'); platform.accessories.splice(platform.accessories.indexOf(unusedDeviceAccessory), 1); } platform.api.unregisterPlatformAccessories(platform.pluginName, platform.platformName, this.unusedDeviceAccessories); // Updates the accessory information for (let i = 0; i < this.deviceAccessories.length; i++) { const deviceAccessory = this.deviceAccessories[i]; let accessoryInformationService = deviceAccessory.getService(Service.AccessoryInformation); if (!accessoryInformationService) { accessoryInformationService = deviceAccessory.addService(Service.AccessoryInformation); } accessoryInformationService .setCharacteristic(Characteristic.Manufacturer, 'Philips') .setCharacteristic(Characteristic.Model, 'Sync Box') .setCharacteristic(Characteristic.FirmwareRevision, state.device.firmwareVersion) .setCharacteristic(Characteristic.SerialNumber, state.device.uniqueId); } if (!platform.config.hideBrightness) { platform.log(`hideBrightness is disabled. Registering Brightness service`) this.setUpBrightness(brightnessState, "Brightness"); } else { platform.log(`hideBrightness is enabled. Removing Brightness service`) this.removeBrightness(brightnessState || powerState, "Brightness"); } this.setUpModeSwitch(powerState, "Power", null) this.setUpModeSwitch(modeState, "Video", "video") this.setUpModeSwitch(modeState, "Music", "music") this.setUpModeSwitch(modeState, "Game", "game") this.setUpModeSwitch(modeState, "Passthrough", "passthrough") this.setUpIntensitySwitch(intensityState, "Subtle", 'subtle') this.setUpIntensitySwitch(intensityState, "Moderate", 'moderate') this.setUpIntensitySwitch(intensityState, "High", 'high') this.setUpIntensitySwitch(intensityState, "Intense", 'intense') for (let i = 1; i <= 4; i++) { this.setUpInputSwitch(inputState, `HDMI ${i}`, `input${i}`) } // Publishes the external accessories (i.e. the TV accessories) if (this.externalAccessories.length > 0) { platform.api.publishExternalAccessories(platform.pluginName, this.externalAccessories); } // Updates all the Characteristics initially this.platform.client.getState(); } }