UNPKG

homebridge-soundtouch-plugins

Version:
120 lines (108 loc) 4.17 kB
import { KeyValue, SourceStatus } from '@bossoq/soundtouch-api' import { deviceIsOn } from './sound-touch-device' import { callbackify, HomebridgeAccessoryWrapper } from './utils' import { Characteristic, Service } from 'homebridge' import { DeviceOnOffListener, SoundTouchDevice } from './types' export abstract class SoundTouchVolume { protected readonly device: SoundTouchDevice protected readonly accessoryWrapper: HomebridgeAccessoryWrapper<SoundTouchDevice> & DeviceOnOffListener protected readonly service: Service public constructor( device: SoundTouchDevice, accessoryWrapper: HomebridgeAccessoryWrapper<SoundTouchDevice> & DeviceOnOffListener ) { this.device = device this.accessoryWrapper = accessoryWrapper this.service = this.initService() if (this.device.volumeSettings.maxValue < 100) this.getVolumeCharacteristic().props.maxValue = Math.min( this.device.volumeSettings.maxValue, 100 ) this.getMuteCharacteristic() .on('get', callbackify(this.isNotMuted.bind(this))) .on('set', callbackify(this.unMuteDevice.bind(this))) this.getVolumeCharacteristic() .on('get', callbackify(this.getVolume.bind(this))) .on('set', callbackify(this.setVolume.bind(this))) .on('change', this.volumeChange.bind(this)) } protected abstract initService(): Service public abstract getVolumeCharacteristic(): Characteristic public abstract getMuteCharacteristic(): Characteristic public async isNotMuted(): Promise<boolean> { const nowPlaying = await this.device.api.getNowPlaying() const isOn = nowPlaying.source !== SourceStatus.standBy if (isOn) { const volume = await this.device.api.getVolume() return !volume.isMuted } return false } public async unMuteDevice(unmute: boolean): Promise<boolean> { let isOn = await deviceIsOn(this.device) if (isOn) { const volume = await this.device.api.getVolume() if ((unmute && volume.isMuted) || (!unmute && !volume.isMuted)) { if (this.device.verbose) this.accessoryWrapper.log( `[${this.accessoryWrapper.getDisplayName()}] ${ unmute ? 'Unmuted' : 'Muted' }` ) return this.device.api.pressKey(KeyValue.mute) } } else if (unmute) { isOn = await this.device.api.pressKey(KeyValue.power) if (isOn) return this.accessoryWrapper.deviceDidTurnOn(true) } return false } public async getVolume(): Promise<number> { const volume = await this.device.api.getVolume() if (this.device.verbose) this.accessoryWrapper.log( `[${this.accessoryWrapper.getDisplayName()}] Current volume is ${ volume.actual }` ) return volume.actual } public async setVolume( volume: number, updateCharacteristic?: boolean ): Promise<boolean> { const volumeCharacteristic = this.getVolumeCharacteristic() const secureVolume = this.secureVolume(volumeCharacteristic, { newValue: volume, oldValue: volumeCharacteristic.value as number, }) if (secureVolume !== undefined) volume = secureVolume if (this.device.verbose) this.accessoryWrapper.log( `[${this.accessoryWrapper.getDisplayName()}] Volume change to ${volume}` ) if (updateCharacteristic === true) volumeCharacteristic.updateValue(volume) return this.device.api.setVolume(volume) } private secureVolume( characteristic: Characteristic, change: { newValue: number; oldValue: number } ): number | undefined { const maxValue = characteristic.props.maxValue if (change.newValue === maxValue && change.oldValue <= maxValue / 2) return Math.max(change.oldValue, this.device.volumeSettings.unmuteValue) return undefined } protected volumeChange(change: { newValue: number; oldValue: number }) { const volumeCharacteristic = this.getVolumeCharacteristic() const newValue = this.secureVolume(volumeCharacteristic, change) if (newValue !== undefined) { setTimeout(() => { volumeCharacteristic.updateValue(newValue) }, 1000) } } }