@jabrown93/homebridge-onkyo
Version:
Homebridge plugin for Onkyo Receivers
803 lines • 38.6 kB
JavaScript
import pollingtoevent from 'polling-to-event';
// @ts-expect-error need to import json
import eiscpDataAll from './eiscp/eiscp-commands.json' with { type: 'json' };
import { PLUGIN_NAME } from './settings.js';
export class OnkyoReceiver {
platform;
eiscp;
setAttempt;
receiver;
cmdMap;
buttons;
state;
m_state;
v_state;
i_state;
interval;
avrManufacturer;
avrSerial;
switchHandling;
tvService;
accessory;
infoService;
tvSpeakerService;
RxInputs;
reachable;
dimmer;
speed;
inputs;
constructor(platform, receiver, accessory) {
this.platform = platform;
this.receiver = receiver;
this.accessory = accessory;
this.reachable = true;
this.inputs = this.receiver.inputs;
this.platform.log.info('**************************************************************');
this.platform.log.info(' GitHub: https://github.com/jabrown93/homebridge-onkyo ');
this.platform.log.info('**************************************************************');
this.platform.log.info('start success...');
this.platform.log.debug('Debug mode enabled');
this.eiscp = platform.connections[receiver.ip_address];
this.setAttempt = 0;
this.platform.log.debug('name %s', this.receiver.name);
this.platform.log.debug('IP %s', this.receiver.ip_address);
this.platform.log.debug('Model %s', this.receiver.model);
this.receiver.zone = (this.receiver.zone ?? 'main').toLowerCase();
this.platform.log.debug('Zone %s', this.receiver.zone);
this.platform.log.debug('Input Mappings %s', this.inputs);
if (this.receiver.volume_type === undefined) {
this.platform.log.warn('WARNING: Your receiveruration is missing the parameter "volume_type". Assuming "none".');
this.receiver.volume_type = 'none';
}
if (this.receiver.filter_inputs === undefined) {
this.platform.log.warn('WARNING: Your receiveruration is missing the parameter "filter_inputs". Assuming "false".');
this.receiver.filter_inputs = false;
}
this.cmdMap = {
main: {
power: 'system-power',
volume: 'master-volume',
muting: 'audio-muting',
input: 'input-selector',
},
zone2: {
power: 'power',
volume: 'volume',
muting: 'muting',
input: 'selector',
},
};
this.receiver.poll_status_interval =
this.receiver.poll_status_interval ?? '0';
this.platform.log.debug('poll_status_interval: %s', this.receiver.poll_status_interval);
this.receiver.max_volume = this.receiver.max_volume ?? 60;
this.platform.log.debug('max_volume: %s', this.receiver.max_volume);
this.receiver.map_volume_100 = this.receiver.map_volume_100 ?? true;
this.platform.log.debug('map_volume_100: %s', this.receiver.map_volume_100);
this.buttons = new Map();
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.REWIND, 'rew');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.FAST_FORWARD, 'ff');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.NEXT_TRACK, 'skip-f');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.PREVIOUS_TRACK, 'skip-r');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.ARROW_UP, 'up');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.ARROW_DOWN, 'down');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.ARROW_LEFT, 'left');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.ARROW_RIGHT, 'right');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.SELECT, 'enter');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.BACK, 'exit');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.EXIT, 'exit');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.PLAY_PAUSE, 'play');
this.buttons.set(this.platform.api.hap.Characteristic.RemoteKey.INFORMATION, 'home');
this.state = false;
this.m_state = false;
this.v_state = 0;
this.i_state = 0;
this.interval = Number.parseInt(this.receiver.poll_status_interval, 10);
this.avrManufacturer = 'Onkyo';
this.avrSerial = this.receiver.serial ?? this.receiver.ip_address;
this.platform.log.debug('avrSerial: %s', this.avrSerial);
this.switchHandling = 'check';
if (this.interval > 10 && this.interval < 100_000) {
this.switchHandling = 'poll';
}
this.eiscp.on('debug', this.eventDebug.bind(this));
this.eiscp.on('error', this.eventError.bind(this));
this.eiscp.on('connect', this.eventConnect.bind(this));
this.eiscp.on('close', this.eventClose.bind(this));
this.eiscp.on(this.cmdMap[this.receiver.zone].power, this.eventSystemPower.bind(this));
this.eiscp.on(this.cmdMap[this.receiver.zone].volume, this.eventVolume.bind(this));
this.eiscp.on(this.cmdMap[this.receiver.zone].muting, this.eventAudioMuting.bind(this));
this.eiscp.on(this.cmdMap[this.receiver.zone].input, this.eventInput.bind(this));
this.setUp();
}
setUp() {
this.createRxInput();
this.polling();
this.infoService = this.createAccessoryInformationService();
this.tvService = this.createTvService();
this.tvSpeakerService = this.createTvSpeakerService();
this.addSources(this.tvService);
if (this.receiver.volume_type && this.receiver.volume_type !== 'none') {
this.platform.log.debug('Creating %s service linked to TV for receiver %s', this.receiver.volume_type, this.receiver.name);
this.createVolumeType(this.tvService);
}
this.platform.api.publishExternalAccessories(PLUGIN_NAME, [this.accessory]);
}
createRxInput() {
const inSets = [];
for (const set in eiscpDataAll.modelsets) {
eiscpDataAll.modelsets[set].forEach(model => {
if (model.includes(this.receiver.model)) {
this.platform.log.debug('Found modelset: %s', set);
inSets.push(set);
}
});
}
// Get list of commands from eiscpData
const eiscpData = eiscpDataAll.commands.main.SLI.values;
// Create a JSON object for inputs from the eiscpData
const inputs = {
Inputs: [],
};
for (const exkey in eiscpData) {
let hold = eiscpData[exkey].name.toString();
if (hold.includes(',')) {
hold = hold.slice(0, hold.indexOf(','));
}
let newExkey = exkey;
if (exkey.includes('“') || exkey.includes('”')) {
newExkey = newExkey.replace(/“/g, '');
newExkey = newExkey.replace(/”/g, '');
}
if (newExkey.includes('UP') ||
newExkey.includes('DOWN') ||
newExkey.includes('QSTN')) {
continue;
}
// Work around specific bug for “26”
if (newExkey === '“26”') {
newExkey = '26';
}
if (!(newExkey in eiscpData) || !('models' in eiscpData[newExkey])) {
continue;
}
const set = eiscpData[newExkey].models;
if (inSets.includes(set)) {
const input = {
code: newExkey,
label: hold,
};
inputs.Inputs.push(input);
}
}
this.RxInputs = inputs;
}
/// ////////////////
// EVENT FUNCTIONS
/// ////////////////
eventDebug(response) {
this.platform.log.debug('eventDebug: %s', response);
}
eventError(response) {
this.platform.log.error('eventError: %s', response);
}
eventConnect(response) {
this.platform.log.debug('eventConnect: %s', response);
this.reachable = true;
}
eventSystemPower(response) {
if (this.state !== (response === 'on')) {
this.platform.log.info('Event - System Power changed: %s', response);
}
this.state = response === 'on';
this.platform.log.debug('eventSystemPower - message: %s, new state %s', response, this.state);
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.Active, this.state);
}
eventAudioMuting(response) {
this.m_state = response === 'on';
this.platform.log.debug('eventAudioMuting - message: %s, new m_state %s', response, this.m_state);
this.tvSpeakerService?.updateCharacteristic(this.platform.api.hap.Characteristic.Mute, this.m_state);
}
eventInput(response) {
if (response) {
let input = JSON.stringify(response);
input = input.replace(/[[\]"]+/g, '');
if (input.includes(',')) {
input = input.slice(0, input.indexOf(','));
}
// Convert to i_state input code
const index = input !== null
? this.RxInputs.Inputs.findIndex(i => i.label === input)
: -1;
if (this.i_state !== index + 1) {
this.platform.log.info('Event - Input changed: %s', input);
}
this.i_state = index + 1;
this.platform.log.debug('eventInput - message: %s - new i_state: %s - input: %s', response, this.i_state, input);
}
else {
// Then invalid Input chosen
this.platform.log.error('eventInput - ERROR - INVALID INPUT - Model does not support selected input.');
}
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.ActiveIdentifier, this.i_state);
}
eventVolume(response) {
if (this.receiver.map_volume_100) {
const volumeMultiplier = (this.receiver.max_volume ?? 1) / 100;
const newVolume = response / volumeMultiplier;
this.v_state = Math.round(newVolume);
this.platform.log.debug('eventVolume - message: %s, new v_state %s PERCENT', response, this.v_state);
}
else {
this.v_state = response;
this.platform.log.debug('eventVolume - message: %s, new v_state %s ACTUAL', response, this.v_state);
}
this.tvSpeakerService?.updateCharacteristic(this.platform.api.hap.Characteristic.Volume, this.v_state);
}
eventClose(response) {
this.platform.log.debug('eventClose: %s', response);
this.reachable = false;
}
/// /////////////////////
// GET AND SET FUNCTIONS
/// /////////////////////
setPowerState(powerOn, context) {
// if context is statuspoll, then we need to ensure that we do not set the actual value
if (context && context === 'statuspoll') {
this.platform.log.debug('setPowerState - polling mode, ignore, state: %s', this.state);
return;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.setAttempt++;
this.state = powerOn;
if (!powerOn) {
this.platform.log.debug('setPowerState - actual mode, power state: %s, switching to OFF', this.state);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].power +
'=standby', error => {
if (error) {
this.state = false;
this.platform.log.error('setPowerState - PWR OFF: ERROR - current state: %s', this.state);
}
});
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.Active, this.state);
return;
}
this.platform.log.debug('setPowerState - actual mode, power state: %s, switching to ON', this.state);
this.eiscp.command(this.receiver.zone + '.' + this.cmdMap[this.receiver.zone].power + '=on', error => {
if (error) {
this.state = false;
this.platform.log.error('setPowerState - PWR ON: ERROR - current state: %s', this.state);
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.Active, 'statuspoll');
return;
}
// If the AVR has just been turned on, apply the default volume
this.platform.log.debug('Attempting to set the default volume to ' +
this.receiver.default_volume);
if (this.receiver.default_volume) {
this.platform.log.info('Setting default volume to ' + this.receiver.default_volume);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].volume +
':' +
this.receiver.default_volume, error => {
if (error) {
this.platform.log.error('Error while setting default volume: %s', error);
}
});
}
// If the AVR has just been turned on, apply the Input default
this.platform.log.debug('Attempting to set the default input selector to ' +
this.receiver.default_input);
// Handle default_input being either a custom label or manufacturer label
let label = this.receiver.default_input;
if (this.inputs) {
this.inputs.forEach(input => {
if (input.input_name === this.receiver.default_input) {
label = input.input_name;
}
else if (input.display_name === this.receiver.default_input) {
label = input.display_name;
}
});
}
const index = label !== null
? this.RxInputs.Inputs.findIndex(i => i.label === label)
: -1;
this.i_state = index + 1;
if (powerOn && label) {
this.platform.log.info('Setting default input selector to ' + label);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].input +
'=' +
label, error => {
if (error) {
this.platform.log.error('Error while setting default input: %s', error);
}
});
}
});
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.Active, this.state);
}
updatePowerState() {
this.platform.log.debug('updatePowerState - current state: %s', this.state);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].power +
'=query', error => {
if (error) {
this.state = false;
this.platform.log.debug('updatePowerState - PWR QRY: ERROR - current state: %s', this.state);
}
});
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.Active, this.state);
}
polling() {
// Status Polling
if (this.switchHandling === 'poll') {
this.platform.log.debug('start long poller..');
// PWR Polling
const statusemitter = pollingtoevent(done => {
this.platform.log.debug('start PWR polling..');
const res = this.getPowerState('statuspoll');
done(null, res, this.setAttempt);
}, {
longpolling: true,
interval: this.interval * 1000,
longpollEventName: 'statuspoll',
});
statusemitter.on('statuspoll', data => {
this.state = data;
this.platform.log.debug('event - PWR status poller - new state: ', this.state);
});
// Audio-Input Polling
const i_statusemitter = pollingtoevent(done => {
this.platform.log.debug('start INPUT polling..');
const res = this.getInputSource('i_statuspoll');
done(null, res, this.setAttempt);
}, {
longpolling: true,
interval: this.interval * 1000,
longpollEventName: 'i_statuspoll',
});
i_statusemitter.on('i_statuspoll', data => {
this.i_state = data;
this.platform.log.debug('event - INPUT status poller - new i_state: ', this.i_state);
});
// Audio-Muting Polling
const m_statusemitter = pollingtoevent(done => {
this.platform.log.debug('start MUTE polling..');
const res = this.getMuteState('m_statuspoll');
done(null, res, this.setAttempt);
}, {
longpolling: true,
interval: this.interval * 1000,
longpollEventName: 'm_statuspoll',
});
m_statusemitter.on('m_statuspoll', data => {
this.m_state = data;
this.platform.log.debug('event - MUTE status poller - new m_state: ', this.m_state);
});
// Volume Polling
const v_statusemitter = pollingtoevent(done => {
this.platform.log.debug('start VOLUME polling..');
const res = this.getVolumeState('v_statuspoll');
done(null, res, this.setAttempt);
}, {
longpolling: true,
interval: this.interval * 1000,
longpollEventName: 'v_statuspoll',
});
v_statusemitter.on('v_statuspoll', data => {
this.v_state = data;
this.platform.log.debug('event - VOLUME status poller - new v_state: ', this.v_state);
});
}
}
getPowerState(context) {
// if context is statuspoll, then we need to request the actual value
if ((!context || context !== 'statuspoll') &&
this.switchHandling === 'poll') {
this.platform.log.debug('getPowerState - polling mode, return state: ', this.state);
return this.state;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.platform.log.debug('getPowerState - actual mode, return state: ', this.state);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].power +
'=query', error => {
if (error) {
this.state = false;
this.platform.log.debug('getPowerState - PWR QRY: ERROR - current state: %s', this.state);
}
});
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.Active, this.state);
return this.state;
}
getVolumeState(context) {
// if context is v_statuspoll, then we need to request the actual value
if ((!context || context !== 'v_statuspoll') &&
this.switchHandling === 'poll') {
this.platform.log.debug('getVolumeState - polling mode, return v_state: ', this.v_state);
return this.v_state;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.platform.log.debug('getVolumeState - actual mode, return v_state: ', this.v_state);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].volume +
'=query', error => {
if (error) {
this.v_state = 0;
this.platform.log.debug('getVolumeState - VOLUME QRY: ERROR - current v_state: %s', this.v_state);
}
});
this.tvSpeakerService?.updateCharacteristic(this.platform.api.hap.Characteristic.Volume, this.v_state);
return this.v_state;
}
setVolumeState(volumeLvl, context) {
// if context is v_statuspoll, then we need to ensure this we do not set the actual value
if (context && context === 'v_statuspoll') {
this.platform.log.debug('setVolumeState - polling mode, ignore, v_state: %s', this.v_state);
return;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.setAttempt++;
// Are we mapping volume to 100%?
if (this.receiver.map_volume_100) {
const volumeMultiplier = this.receiver.max_volume
? this.receiver.max_volume / 100
: 100;
const newVolume = volumeMultiplier * volumeLvl;
this.v_state = Math.round(newVolume);
this.platform.log.debug('setVolumeState - actual mode, PERCENT, volume v_state: %s', this.v_state);
}
else if (volumeLvl > (this.receiver.max_volume ?? 100)) {
// Determine if max_volume threshold breached, if so set to max.
this.v_state = this.receiver.max_volume ?? 100;
this.platform.log.debug('setVolumeState - VOLUME LEVEL of: %s exceeds max_volume: %s. Resetting to max.', volumeLvl, this.receiver.max_volume);
}
else {
// Must be using actual volume number
this.v_state = volumeLvl;
this.platform.log.debug('setVolumeState - actual mode, ACTUAL volume v_state: %s', this.v_state);
}
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].volume +
':' +
this.v_state, error => {
if (error) {
this.v_state = 0;
this.platform.log.debug('setVolumeState - VOLUME : ERROR - current v_state: %s', this.v_state);
}
});
this.tvSpeakerService?.updateCharacteristic(this.platform.api.hap.Characteristic.Volume, this.v_state);
}
setVolumeRelative(volumeDirection, context) {
// if context is v_statuspoll, then we need to ensure this we do not set the actual value
if (context && context === 'v_statuspoll') {
this.platform.log.debug('setVolumeRelative - polling mode, ignore, v_state: %s', this.v_state);
return;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.setAttempt++;
if (volumeDirection ===
this.platform.api.hap.Characteristic.VolumeSelector.INCREMENT) {
this.platform.log.debug('setVolumeRelative - VOLUME : level-up');
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].volume +
':level-up', error => {
if (error) {
this.v_state = 0;
this.platform.log.error('setVolumeRelative - VOLUME : ERROR - current v_state: %s', this.v_state);
}
});
}
else if (volumeDirection ===
this.platform.api.hap.Characteristic.VolumeSelector.DECREMENT) {
this.platform.log.debug('setVolumeRelative - VOLUME : level-down');
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].volume +
':level-down', error => {
if (error) {
this.v_state = 0;
this.platform.log.error('setVolumeRelative - VOLUME : ERROR - current v_state: %s', this.v_state);
}
});
}
else {
this.platform.log.error('setVolumeRelative - VOLUME : ERROR - unknown direction sent');
}
this.tvSpeakerService?.updateCharacteristic(this.platform.api.hap.Characteristic.Volume, this.v_state);
}
getMuteState(context) {
// if context is m_statuspoll, then we need to request the actual value
if ((!context || context !== 'm_statuspoll') &&
this.switchHandling === 'poll') {
this.platform.log.debug('getMuteState - polling mode, return m_state: ', this.m_state);
return this.m_state;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.platform.log.debug('getMuteState - actual mode, return m_state: ', this.m_state);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].muting +
'=query', error => {
if (error) {
this.m_state = false;
this.platform.log.debug('getMuteState - MUTE QRY: ERROR - current m_state: %s', this.m_state);
}
});
this.tvSpeakerService?.updateCharacteristic(this.platform.api.hap.Characteristic.Mute, this.m_state);
return this.m_state;
}
setMuteState(muteOn, context) {
// if context is m_statuspoll, then we need to ensure this we do not set the actual value
if (context && context === 'm_statuspoll') {
this.platform.log.debug('setMuteState - polling mode, ignore, m_state: %s', this.m_state);
return this.m_state;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.setAttempt++;
this.m_state = muteOn;
if (this.m_state) {
this.platform.log.debug('setMuteState - actual mode, mute m_state: %s, switching to ON', this.m_state);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].muting +
'=on', error => {
if (error) {
this.m_state = false;
this.platform.log.error('setMuteState - MUTE ON: ERROR - current m_state: %s', this.m_state);
}
});
}
else {
this.platform.log.debug('setMuteState - actual mode, mute m_state: %s, switching to OFF', this.m_state);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].muting +
'=off', error => {
if (error) {
this.m_state = false;
this.platform.log.error('setMuteState - MUTE OFF: ERROR - current m_state: %s', this.m_state);
}
});
}
this.tvSpeakerService?.updateCharacteristic(this.platform.api.hap.Characteristic.Mute, this.m_state);
return this.m_state;
}
getInputSource(context) {
// if context is i_statuspoll, then we need to request the actual value
if ((!context || context !== 'i_statuspoll') &&
this.switchHandling === 'poll') {
this.platform.log.debug('getInputState - polling mode, return i_state: ', this.i_state);
return this.i_state;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.platform.log.debug('getInputState - actual mode, return i_state: ', this.i_state);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].input +
'=query', error => {
if (error) {
this.i_state = 1;
this.platform.log.error('getInputState - INPUT QRY: ERROR - current i_state: %s', this.i_state);
}
});
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.ActiveIdentifier, this.i_state);
return this.i_state;
}
setInputSource(source, context) {
// if context is i_statuspoll, then we need to ensure this we do not set the actual value
if (context && context === 'i_statuspoll') {
this.platform.log.info('setInputState - polling mode, ignore, i_state: %s', this.i_state);
return;
}
if (!this.receiver.ip_address) {
this.platform.log.error('Ignoring request; No ip_address defined.');
throw new Error('No ip_address defined.');
}
this.setAttempt++;
this.i_state = source;
const label = this.RxInputs.Inputs[this.i_state - 1].label;
this.platform.log.debug('setInputState - actual mode, ACTUAL input i_state: %s - label: %s', this.i_state, label);
this.eiscp.command(this.receiver.zone +
'.' +
this.cmdMap[this.receiver.zone].input +
':' +
label, error => {
if (error) {
this.platform.log.error('setInputState - INPUT : ERROR - current i_state:%s - Source:%s', this.i_state, source.toString());
}
});
this.tvService?.updateCharacteristic(this.platform.api.hap.Characteristic.ActiveIdentifier, this.i_state);
}
remoteKeyPress(button) {
if (this.buttons.get(button)) {
const press = this.buttons.get(button);
this.platform.log.debug('remoteKeyPress - INPUT: pressing key %s', press);
this.eiscp.command(this.receiver.zone + '.setup=' + press, error => {
if (error) {
this.i_state = 1;
this.platform.log.error('remoteKeyPress - INPUT: ERROR pressing button %s', press);
}
});
}
else {
this.platform.log.error('Remote button %d not supported.', button);
}
}
identify(callback) {
this.platform.log.info('Identify requested! %s', this.receiver.ip_address);
callback(); // success
}
/// /////////////////////
// TV SERVICE FUNCTIONS
/// /////////////////////
addSources(service) {
// If input name mappings are provided, use them.
// Option to only receiver specified inputs with filter_inputs
this.platform.log.debug('Supported inputs', this.RxInputs.Inputs);
if (this.receiver.filter_inputs && this.inputs) {
// Check the RxInputs.Inputs items to see if each exists in this.inputs. Return new array of those that do.
this.RxInputs.Inputs = this.RxInputs.Inputs.filter(rxinput => {
return this.inputs?.some(input => {
return input.input_name === rxinput.label;
});
});
}
this.platform.log.debug(this.RxInputs.Inputs);
// Create final array of inputs, using any labels defined in the receiver's inputs to override the default labels
return this.RxInputs.Inputs.map((i, index) => {
const hapId = index + 1;
let inputName = i.label;
if (this.inputs) {
this.inputs.forEach(input => {
if (input.input_name === i.label) {
this.platform.log.debug('Found input mapping for %s to %s ', i.label, input.display_name);
inputName = input.display_name;
}
});
}
return this.setupInput(i.code, inputName, hapId, service);
});
}
setupInput(inputCode, name, hapId, television) {
const normalizedName = name.replace('-', ' ');
const input = this.accessory.addService(this.platform.api.hap.Service.InputSource, `${this.receiver.name} ${normalizedName}`, inputCode);
const inputSourceType = this.platform.api.hap.Characteristic.InputSourceType.HDMI;
input
.setCharacteristic(this.platform.api.hap.Characteristic.Identifier, hapId)
.setCharacteristic(this.platform.api.hap.Characteristic.ConfiguredName, normalizedName)
.setCharacteristic(this.platform.api.hap.Characteristic.IsConfigured, this.platform.api.hap.Characteristic.IsConfigured.CONFIGURED)
.setCharacteristic(this.platform.api.hap.Characteristic.InputSourceType, inputSourceType);
input
.getCharacteristic(this.platform.api.hap.Characteristic.ConfiguredName)
.setProps({
perms: ["pr" /* this.platform.api.hap.Perms.PAIRED_READ */],
});
television.addLinkedService(input);
return input;
}
createAccessoryInformationService() {
const informationService = this.accessory.getService(this.platform.api.hap.Service.AccessoryInformation) ??
this.accessory.addService(this.platform.api.hap.Service.AccessoryInformation);
informationService
.setCharacteristic(this.platform.api.hap.Characteristic.Manufacturer, this.avrManufacturer)
.setCharacteristic(this.platform.api.hap.Characteristic.Model, this.receiver.model)
.setCharacteristic(this.platform.api.hap.Characteristic.SerialNumber, this.avrSerial)
.setCharacteristic(this.platform.api.hap.Characteristic.FirmwareRevision, 'info.version')
.setCharacteristic(this.platform.api.hap.Characteristic.Name, this.receiver.name);
return informationService;
}
createVolumeType(service) {
if (this.receiver.volume_type === 'dimmer') {
this.dimmer = this.accessory.addService(this.platform.api.hap.Service.Lightbulb, this.receiver.name + ' Volume', 'dimmer');
this.dimmer
.getCharacteristic(this.platform.api.hap.Characteristic.On)
// Inverted logic taken from https://github.com/langovoi/homebridge-upnp
.onGet(() => {
return !this.getMuteState(null);
})
.onSet(value => this.setMuteState(!value, ''));
this.dimmer
.addCharacteristic(this.platform.api.hap.Characteristic.Brightness)
.onGet(this.getVolumeState.bind(this))
.onSet(this.setVolumeState.bind(this));
service.addLinkedService(this.dimmer);
}
else if (this.receiver.volume_type === 'speed') {
this.speed = this.accessory.addService(this.platform.api.hap.Service.Fan, this.receiver.name + ' Volume', 'speed');
this.speed
.getCharacteristic(this.platform.api.hap.Characteristic.On)
// Inverted logic taken from https://github.com/langovoi/homebridge-upnp
.onGet(context => {
return !this.getMuteState(context);
})
.onSet((value, context) => this.setMuteState(!value, context));
this.speed
.addCharacteristic(this.platform.api.hap.Characteristic.RotationSpeed)
.onGet(this.getVolumeState.bind(this))
.onSet(this.setVolumeState.bind(this));
service.addLinkedService(this.speed);
}
}
createTvService() {
this.platform.log.debug('Creating TV service for receiver %s', this.receiver.name);
const tvService = this.accessory.getService(this.platform.api.hap.Service.Television) ??
this.accessory.addService(this.platform.api.hap.Service.Television, this.receiver.name);
tvService
.getCharacteristic(this.platform.api.hap.Characteristic.ConfiguredName)
.setValue(this.receiver.name)
.setProps({
perms: ["pr" /* this.platform.api.hap.Perms.PAIRED_READ */],
});
tvService.setCharacteristic(this.platform.api.hap.Characteristic.SleepDiscoveryMode, this.platform.api.hap.Characteristic.SleepDiscoveryMode
.ALWAYS_DISCOVERABLE);
tvService
.getCharacteristic(this.platform.api.hap.Characteristic.Active)
.onGet(this.getPowerState.bind(this))
.onSet(this.setPowerState.bind(this));
tvService
.getCharacteristic(this.platform.api.hap.Characteristic.ActiveIdentifier)
.onSet(this.setInputSource.bind(this))
.onGet(this.getInputSource.bind(this));
tvService
.getCharacteristic(this.platform.api.hap.Characteristic.RemoteKey)
.onSet(this.remoteKeyPress.bind(this));
return tvService;
}
createTvSpeakerService() {
this.platform.log.debug('Creating TV Speaker service for receiver `%s`', this.receiver.name);
const tvSpeakerService = this.accessory.getService(this.platform.api.hap.Service.TelevisionSpeaker) ??
this.accessory.addService(this.platform.api.hap.Service.TelevisionSpeaker, this.receiver.name + ' Volume', 'tvSpeakerService');
tvSpeakerService
.setCharacteristic(this.platform.api.hap.Characteristic.Active, this.platform.api.hap.Characteristic.Active.ACTIVE)
.setCharacteristic(this.platform.api.hap.Characteristic.VolumeControlType, this.platform.api.hap.Characteristic.VolumeControlType.ABSOLUTE);
tvSpeakerService
.getCharacteristic(this.platform.api.hap.Characteristic.VolumeSelector)
.onSet(this.setVolumeRelative.bind(this));
tvSpeakerService
.getCharacteristic(this.platform.api.hap.Characteristic.Mute)
.onGet(this.getMuteState.bind(this))
.onSet(this.setMuteState.bind(this));
tvSpeakerService
.addCharacteristic(this.platform.api.hap.Characteristic.Volume)
.onGet(this.getVolumeState.bind(this))
.onSet(this.setVolumeState.bind(this));
this.tvService?.addLinkedService(tvSpeakerService);
return tvSpeakerService;
}
}
//# sourceMappingURL=onkyoReceiver.js.map