homebridge-dune-hd
Version:
Homebridge Plugin to control your Dune HD.
894 lines (866 loc) • 108 kB
JavaScript
"use strict";
const PLATFORM_NAME = 'duneHDPlugin';
const PLUGIN_NAME = 'homebridge-dune-hd';
const request = require('http');
const udp = require('dgram');
// Declarative list of optional stateless switches used to build/remove services consistently.
const STATELESS_SWITCH_CONFIGS = [
{ propertyName: 'cursorUp', serviceName: 'Cursor Up', uniqueId: 'CataNicoGaTa-31', configKey: 'cursorUpB', commandName: 'CURSOR UP' },
{ propertyName: 'cursorDown', serviceName: 'Cursor Down', uniqueId: 'CataNicoGaTa-32', configKey: 'cursorDownB', commandName: 'CURSOR DOWN' },
{ propertyName: 'cursorLeft', serviceName: 'Cursor Left', uniqueId: 'CataNicoGaTa-33', configKey: 'cursorLeftB', commandName: 'CURSOR LEFT' },
{ propertyName: 'cursorRight', serviceName: 'Cursor Right', uniqueId: 'CataNicoGaTa-34', configKey: 'cursorRightB', commandName: 'CURSOR RIGHT' },
{ propertyName: 'cursorEnter', serviceName: 'Cursor Enter', uniqueId: 'CataNicoGaTa-35', configKey: 'cursorEnterB', commandName: 'CURSOR ENTER' },
{ propertyName: 'searchB', serviceName: 'Search', uniqueId: 'CataNicoGaTa-36', configKey: 'searchB', commandName: 'SEARCH' },
{ propertyName: 'backButton', serviceName: 'Back', uniqueId: 'CataNicoGaTa-37', configKey: 'backButtonB', commandName: 'BACK' },
{ propertyName: 'infoButton', serviceName: 'Info', uniqueId: 'CataNicoGaTa-44', configKey: 'infoB', commandName: 'INFO' },
{ propertyName: 'pageUp', serviceName: 'Page Up', uniqueId: 'CataNicoGaTa-50', configKey: 'pageUpB', commandName: 'PAGE UP' },
{ propertyName: 'pageDown', serviceName: 'Page Down', uniqueId: 'CataNicoGaTa-51', configKey: 'pageDownB', commandName: 'PAGE DOWN' },
{ propertyName: 'popUpMenu', serviceName: 'Pop-Up Menu', uniqueId: 'CataNicoGaTa-52', configKey: 'popUpMenuB', commandName: 'POP-UP MENU' },
{ propertyName: 'previous', serviceName: 'Previous', uniqueId: 'CataNicoGaTa-38', configKey: 'mediaButtons', commandName: 'PREVIOUS' },
{ propertyName: 'next', serviceName: 'Next', uniqueId: 'CataNicoGaTa-39', configKey: 'mediaButtons', commandName: 'NEXT' },
{ propertyName: 'rewindButton', serviceName: 'Rewind', uniqueId: 'CataNicoGaTa-46', configKey: 'mediaButtons', commandName: 'REWIND' },
{ propertyName: 'forwardButton', serviceName: 'Forward', uniqueId: 'CataNicoGaTa-80', configKey: 'mediaButtons', commandName: 'FORWARD' },
{ propertyName: 'red', serviceName: 'Red', uniqueId: 'CataNicoGaTa-53', configKey: 'redB', commandName: 'RED' },
{ propertyName: 'green', serviceName: 'Green', uniqueId: 'CataNicoGaTa-54', configKey: 'greenB', commandName: 'GREEN' },
{ propertyName: 'blue', serviceName: 'Blue', uniqueId: 'CataNicoGaTa-55', configKey: 'blueB', commandName: 'BLUE' },
{ propertyName: 'yellow', serviceName: 'Yellow', uniqueId: 'CataNicoGaTa-56', configKey: 'yellowB', commandName: 'YELLOW' },
{ propertyName: 'audio', serviceName: 'Audio', uniqueId: 'CataNicoGaTa-57', configKey: 'audioB', commandName: 'AUDIO' },
{ propertyName: 'subtitle', serviceName: 'Subtitle', uniqueId: 'CataNicoGaTa-58', configKey: 'subtitleB', commandName: 'SUBTITLE' },
{ propertyName: 'repeat', serviceName: 'Repeat', uniqueId: 'CataNicoGaTa-63', configKey: 'repeatB', commandName: 'REPEAT' },
{ propertyName: 'pip', serviceName: 'Shuffle-PIP', uniqueId: 'CataNicoGaTa-64', configKey: 'pipB', commandName: 'PIP' },
{ propertyName: 'selectB', serviceName: 'Select', uniqueId: 'CataNicoGaTa-65', configKey: 'selectB', commandName: 'SELECT' },
{ propertyName: 'mute', serviceName: 'Mute', uniqueId: 'CataNicoGaTa-9001', configKey: 'muteB', commandName: 'MUTE' },
{ propertyName: 'record', serviceName: 'Record', uniqueId: 'CataNicoGaTa-9002', configKey: 'recordB', commandName: 'RECORD' },
{ propertyName: 'movie', serviceName: 'Movie', uniqueId: 'CataNicoGaTa-9003', configKey: 'movieB', commandName: 'MOVIE' },
{ propertyName: 'music', serviceName: 'Music', uniqueId: 'CataNicoGaTa-9004', configKey: 'musicB', commandName: 'MUSIC' },
{ propertyName: 'tvB', serviceName: 'TV', uniqueId: 'CataNicoGaTa-9005', configKey: 'tvB', commandName: 'TV' },
{ propertyName: 'ejectB', serviceName: 'Eject', uniqueId: 'CataNicoGaTa-9006', configKey: 'ejectB', commandName: 'EJECT' },
{ propertyName: 'modeB', serviceName: 'Mode', uniqueId: 'CataNicoGaTa-9007', configKey: 'modeB', commandName: 'LIGHT' },
{ propertyName: 'slowB', serviceName: 'Slow', uniqueId: 'CataNicoGaTa-9008', configKey: 'slowB', commandName: 'SLOW' },
{ propertyName: 'mouseB', serviceName: 'Mouse', uniqueId: 'CataNicoGaTa-9009', configKey: 'mouseB', commandName: 'MOUSE' },
{ propertyName: 'clear', serviceName: 'Clear', uniqueId: 'CataNicoGaTa-40', configKey: 'clearB', commandName: 'CLEAR' },
{ propertyName: 'zoom', serviceName: 'Zoom', uniqueId: 'CataNicoGaTa-60', configKey: 'zoomB', commandName: 'ZOOM' },
{ propertyName: 'setup', serviceName: 'Setup', uniqueId: 'CataNicoGaTa-45', configKey: 'setupB', commandName: 'SETUP' },
{ propertyName: 'topMenu', serviceName: 'Top Menu', uniqueId: 'CataNicoGaTa-41', configKey: 'topMenuB', commandName: 'TOP MENU' },
{ propertyName: 'angle', serviceName: 'Angle', uniqueId: 'CataNicoGaTa-59', configKey: 'angleB', commandName: 'ANGLE' },
{ propertyName: 'recentB', serviceName: 'Recent', uniqueId: 'CataNicoGaTa-X09', configKey: 'recentB', commandName: 'RECENT' },
];
// Shared Dune remote command definitions used for both command logging and IR URL generation.
const REMOTE_COMMAND_DEFINITIONS = [
{ code: 'A05F', label: 'Power On', buttons: ['POWER ON'] },
{ code: 'A15E', label: 'Power Off', buttons: ['POWER OFF'] },
{ code: '9E61', label: 'Recent', buttons: ['RECENT'] },
{ code: 'EA15', label: 'Cursor Up', buttons: ['CURSOR UP'] },
{ code: 'E916', label: 'Cursor Down', buttons: ['CURSOR DOWN'] },
{ code: 'E817', label: 'Cursor Left', buttons: ['CURSOR LEFT'] },
{ code: 'E718', label: 'Cursor Right', buttons: ['CURSOR RIGHT'] },
{ code: 'EB14', label: 'Enter', buttons: ['CURSOR ENTER'] },
{ code: 'F906', label: 'Search', buttons: ['SEARCH'] },
{ code: 'FB04', label: 'Back', buttons: ['BACK'] },
{ code: 'B748', label: 'Play/Play-Pause', buttons: ['PLAY', 'PLAY/PAUSE'] },
{ code: 'E11E', label: 'Pause', buttons: ['PAUSE'] },
{ code: 'E619', label: 'Stop', buttons: ['STOP'] },
{ code: 'B649', label: 'Previous Chapter', buttons: ['PREVIOUS'] },
{ code: 'E21D', label: 'Next Chapter', buttons: ['NEXT'] },
{ code: 'AF50', label: 'Information', buttons: ['INFO'] },
{ code: 'E31C', label: 'Rewind', buttons: ['REWIND'] },
{ code: 'E41B', label: 'Forward', buttons: ['FORWARD'] },
{ code: 'B44B', label: 'Page Up', buttons: ['PAGE UP'] },
{ code: 'B34C', label: 'Page Down', buttons: ['PAGE DOWN'] },
{ code: 'F807', label: 'Pop-Up Menu', buttons: ['POP-UP MENU'] },
{ code: 'BF40', label: 'Red', buttons: ['RED'] },
{ code: 'E01F', label: 'Green', buttons: ['GREEN'] },
{ code: 'FF00', label: 'Yellow', buttons: ['YELLOW'] },
{ code: 'BE41', label: 'Blue', buttons: ['BLUE'] },
{ code: 'BB44', label: 'Audio', buttons: ['AUDIO'] },
{ code: 'AB54', label: 'Subtitle', buttons: ['SUBTITLE'] },
{ code: 'B04F', label: 'Repeat/Mouse', buttons: ['REPEAT', 'MOUSE'] },
{ code: 'B847', label: 'PIP/Movie', buttons: ['PIP', 'MOVIE'] },
{ code: 'BD42', label: 'Select', buttons: ['SELECT'] },
{ code: 'AD52', label: 'Volume Up', buttons: ['VOLUME UP'] },
{ code: 'AC53', label: 'Volume Down', buttons: ['VOLUME DOWN'] },
{ code: 'B946', label: 'Mute', buttons: ['MUTE'] },
{ code: '9F60', label: 'Record', buttons: ['RECORD'] },
{ code: 'A758', label: 'Music', buttons: ['MUSIC'] },
{ code: '9C63', label: 'TV', buttons: ['TV'] },
{ code: 'EF10', label: 'Eject', buttons: ['EJECT'] },
{ code: 'light', label: 'Light', buttons: ['LIGHT'] },
{ code: 'E51A', label: 'Slow', buttons: ['SLOW'] },
{ code: 'FA05', label: 'Clear', buttons: ['CLEAR'] },
{ code: 'FD02', label: 'Zoom', buttons: ['ZOOM'] },
{ code: 'B14E', label: 'Setup', buttons: ['SETUP'] },
{ code: 'AE51', label: 'Top Menu', buttons: ['TOP MENU'] },
{ code: 'B24D', label: 'Angle', buttons: ['ANGLE'] },
];
const BUTTON_IR_CODE_MAP = REMOTE_COMMAND_DEFINITIONS.reduce((map, definition) => {
for (const buttonName of definition.buttons) {
map[buttonName] = definition.code;
}
return map;
}, {});
const COMMAND_NAME_MATCHES = [
{ token: 'standby', label: 'Standby' },
{ token: 'position', label: 'New Position' },
...REMOTE_COMMAND_DEFINITIONS.map((definition) => ({ token: definition.code, label: definition.label })),
{ token: 'getDeviceInfo', label: 'Get Device Information' },
{ token: 'seek', label: 'Searching' },
];
module.exports = (api) => {
api.registerPlatform(PLUGIN_NAME, PLATFORM_NAME, duneHDPlatform, true);
};
//// Platform/////////////////////////////////////////////////////////////////////////////////////////////////
class duneHDPlatform {
constructor(log, config, api) {
this.log = log;
this.config = config;
this.api = api;
this.Service = this.api.hap.Service;
this.Characteristic = this.api.hap.Characteristic;
this.config.name = this.config.name || 'Dune HD';
this.config.newPlatformUUID = this.config.newPlatformUUID || false;
// this is used to track restored cached accessories
this.accessories = [];
this.log.debug('Finished initializing platform:', this.config.name);
this.api.on('didFinishLaunching', () => {
log.debug('didFinishLaunching callback');
this.iniDevice();
});
}
configureAccessory(accessory) {
this.log.info('Loading accessory from cache:', accessory.displayName);
this.accessories.push(accessory);
}
iniDevice() {
if (this.config.newPlatformUUID === false) {
this.duneHDDevice =
{
duneHDUniqueId: 'nicocatagameztanarro',
duneHDDisplayName: `${this.config.name}`
};
}
if (this.config.newPlatformUUID === true) {
this.duneHDDevice =
{
duneHDUniqueId: `${this.config.name}catanico`,
duneHDDisplayName: `${this.config.name}`
};
this.log.debug('Generationg a new UUID');
}
const uuid = this.api.hap.uuid.generate(this.duneHDDevice.duneHDUniqueId);
this.log.debug('Adding new accessory:', this.duneHDDevice.duneHDDisplayName);
const accessory = new this.api.platformAccessory(this.duneHDDevice.duneHDDisplayName, uuid);
accessory.category = 35;
accessory.context.device = this.duneHDDevice;
new duneHDAccessory(this, accessory);
this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]);
}
removeAccessory(accessory) {
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
}
}
class duneHDAccessory {
constructor(platform, accessory) {
this.platform = platform;
this.accessory = accessory;
this.config = platform.config;
this.DUNEHD_IP = this.config.ip;
this.DUNEHD_PORT = this.config.port || 80;
this.statelessTimeOut = 1000;
this.turnOffCommand = false;
this.turnOnCommand = false;
//////Initial Switch and sensors state///////////////////////////////////////////////////////////////////////////////////////////////
this.powerState = false;
this.playBackState = [false, false, false];
this.powerStateTV = 0;
this.currentVolume = 0;
this.currentMuteState = true;
this.currentVolumeSwitch = false;
this.inputID = 1;
this.mediaState = 4;
this.videoState = false;
this.audioState = false;
this.chapterTime = '';
this.inputName = 'Media Title';
this.mediaDuration = 'Runtime';
this.mediaInformation = 'Video Information';
this.mediaChapter = 'Current Chapter';
this.mediaAudioFormat = 'Audio Format';
this.language = 'Audio Language';
this.subtitleLanguage = '';
this.showState = false;
this.httpNotResponding = 0;
this.pollInFlight = false;
this.turnOffAllUsed = false;
this.counter = 0;
/////MovieConstants
this.currentMovieProgress = 0;
this.currentMovieProgressState = false;
this.movieElapsed = 0;
this.currentMoviePosition = 0;
this.movieRemaining = 0;
this.bluryaDVD = false;
////Connection parameters
this.reconnectionTry = 10;
//Device Information//////////////////////////////////////////////////////////////////////////////////////
this.config.name = platform.config.name || 'Dune HD';
this.config.ip = platform.config.ip;
this.config.manufacturer = platform.config.manufacturer || 'Dune HD';
this.config.pollingInterval = platform.config.pollingInterval || 1000;
this.config.modelName = platform.config.modelName || 'Real Vision 4K';
this.config.serialN = platform.config.serialN || 'B210U71647033894';
this.config.mediaButtons = platform.config.mediaButtons || false;
this.config.volume = platform.config.volume || false;
this.config.cursorUpB = platform.config.cursorUpB || false;
this.config.cursorDownB = platform.config.cursorDownB || false;
this.config.cursorLeftB = platform.config.cursorLeftB || false;
this.config.cursorRightB = platform.config.cursorRightB || false;
this.config.cursorEnterB = platform.config.cursorEnterB || false;
this.config.searchB = platform.config.searchB || false;
this.config.backButtonB = platform.config.backButtonB || false;
this.config.infoB = platform.config.infoB || false;
this.config.pageUpB = platform.config.pageUpB || false;
this.config.pageDownB = platform.config.pageDownB || false;
this.config.popUpMenuB = platform.config.popUpMenuB || false;
this.config.redB = platform.config.redB || false;
this.config.yellowB = platform.config.yellowB || false;
this.config.blueB = platform.config.blueB || false;
this.config.audioB = platform.config.audioB || false;
this.config.greenB = platform.config.greenB || false;
this.config.subtitleB = platform.config.subtitleB || false;
this.config.repeatB = platform.config.repeatB || false;
this.config.pipB = platform.config.pipB || false;
this.config.selectB = platform.config.selectB || false;
this.config.movieControl = platform.config.movieControl || false;
this.config.powerB = platform.config.powerB || false;
this.config.muteB = platform.config.muteB || false;
this.config.recordB = platform.config.recordB || false;
this.config.movieB = platform.config.movieB || false;
this.config.musicB = platform.config.musicB || false;
this.config.tvB = platform.config.tvB || false;
this.config.ejectB = platform.config.ejectB || false;
this.config.modeB = platform.config.modeB || false;
this.config.slowB = platform.config.slowB || false;
this.config.mouseB = platform.config.mouseB || false;
this.config.clearB = platform.config.clearB || false;
this.config.zoomB = platform.config.zoomB || false;
this.config.setupB = platform.config.setupB || false;
this.config.topMenuB = platform.config.topMenuB || false;
this.config.angleB = platform.config.angleB || false;
this.config.recentB = platform.config.recentB || false;
this.config.changeDimmersToFan = platform.config.changeDimmersToFan || false;
this.config.remainMovieTimer = platform.config.remainMovieTimer || false;
this.config.infoToMenu = platform.config.infoToMenu || false;
////Checking if the necessary information was given by the user////////////////////////////////////////////////////
try {
if (!this.config.ip) {
throw new Error(`Dune HD IP address is required for ${this.config.name}`);
}
} catch (error) {
this.platform.log(error);
this.platform.log('Failed to create platform device, missing mandatory information!');
this.platform.log('Please check your device config!');
return;
}
////////////Get Model/////////////////////
this.accessory.getService(this.platform.Service.AccessoryInformation)
.setCharacteristic(this.platform.Characteristic.Manufacturer, this.config.manufacturer)
.setCharacteristic(this.platform.Characteristic.Model, this.config.modelName)
.setCharacteristic(this.platform.Characteristic.SerialNumber, this.config.serialN)
.setCharacteristic(this.platform.Characteristic.FirmwareRevision, '1.3.1');
// set accessory information//////////////////////////////////////////////////////////////////////////////////////////
/////////Television Controls///////////////////////////////////////////////////////////////////////////////////////////
// add the tv service
this.tvService = this.accessory.getService(this.config.name) ||
this.accessory.addService(this.platform.Service.Television, this.config.name, 'CataNicoGaTa-7');
this.tvService.setCharacteristic(this.platform.Characteristic.ConfiguredName, this.config.name);
this.tvService.setCharacteristic(this.platform
.Characteristic.SleepDiscoveryMode, this.platform.Characteristic.SleepDiscoveryMode.ALWAYS_DISCOVERABLE);
this.tvService.getCharacteristic(this.platform.Characteristic.Active)
.on('set', (newValue, callback) => {
this.platform.log.debug('Set Dune HD Active to: ' + newValue);
if (newValue === 1) {
this.newPowerState(true);
this.turnOnCommand = true;
this.turnOffCommand = false;
this.sending([this.pressedButton('POWER ON')]);
// this.WakeupOnLAN();
// this.sending([this.pressedButton('POWER ON')]);
}
else {
this.sending([this.pressedButton('STOP')]);
this.newPowerState(false);
this.turnOffAll();
this.turnOffCommand = true;
this.turnOnCommand = false;
// this.sending(["http://" + this.DUNEHD_IP + ":" + this.DUNEHD_PORT + "/cgi-bin/do?cmd=standby&result_syntax=json"]);
setTimeout(() => {
this.sending([this.pressedButton('POWER OFF')]);
}, 1000);
}
callback(null);
})
.on('get', (callback) => {
let currentValue = this.powerStateTV;
callback(null, currentValue);
});
this.tvService.getCharacteristic(this.platform.Characteristic.ClosedCaptions)
.on('get', (callback) => {
this.platform.log.debug('Subtitle GET On');
let currentValue = 0;
callback(null, currentValue);
})
.on('set', (value, callback) => {
this.platform.log.debug('Subtitle SET On:', value);
if (value === 1) {
this.sending([this.pressedButton('SUBTITLE')]);
}
this.tvService.updateCharacteristic(this.platform.Characteristic.ClosedCaptions, 0);
callback(null);
});
this.tvService.getCharacteristic(this.platform.Characteristic.RemoteKey)
.on('set', (newValue, callback) => {
switch (newValue) {
case this.platform.Characteristic.RemoteKey.REWIND: {
this.platform.log.debug('set Remote Key Pressed: REWIND');
this.sending([this.pressedButton('REWIND')]);
break;
}
case this.platform.Characteristic.RemoteKey.FAST_FORWARD: {
this.platform.log.debug('set Remote Key Pressed: FAST_FORWARD');
this.sending([this.pressedButton('FORWARD')]);
break;
}
case this.platform.Characteristic.RemoteKey.NEXT_TRACK: {
this.platform.log.debug('set Remote Key Pressed: NEXT_TRACK');
this.sending([this.pressedButton('NEXT')]);
break;
}
case this.platform.Characteristic.RemoteKey.PREVIOUS_TRACK: {
this.platform.log.debug('set Remote Key Pressed: PREVIOUS_TRACK');
this.sending([this.pressedButton('PREVIOUS')]);
break;
}
case this.platform.Characteristic.RemoteKey.ARROW_UP: {
this.platform.log.debug('set Remote Key Pressed: ARROW_UP');
this.sending([this.pressedButton('CURSOR UP')]);
break;
}
case this.platform.Characteristic.RemoteKey.ARROW_DOWN: {
this.platform.log.debug('set Remote Key Pressed: ARROW_DOWN');
this.sending([this.pressedButton('CURSOR DOWN')]);
break;
}
case this.platform.Characteristic.RemoteKey.ARROW_LEFT: {
this.platform.log.debug('set Remote Key Pressed: ARROW_LEFT');
this.sending([this.pressedButton('CURSOR LEFT')]);
break;
}
case this.platform.Characteristic.RemoteKey.ARROW_RIGHT: {
this.platform.log.debug('set Remote Key Pressed: ARROW_RIGHT');
this.sending([this.pressedButton('CURSOR RIGHT')]);
break;
}
case this.platform.Characteristic.RemoteKey.SELECT: {
this.platform.log.debug('set Remote Key Pressed: SELECT');
this.sending([this.pressedButton('CURSOR ENTER')]);
break;
}
case this.platform.Characteristic.RemoteKey.BACK: {
this.platform.log.debug('set Remote Key Pressed: BACK');
this.sending([this.pressedButton('BACK')]);
break;
}
case this.platform.Characteristic.RemoteKey.EXIT: {
this.platform.log.debug('set Remote Key Pressed: EXIT');
// Dune maps this action to Top Menu (Home Menu is not a valid key in pressedButton()).
this.sending([this.pressedButton('TOP MENU')]);
break;
}
case this.platform.Characteristic.RemoteKey.PLAY_PAUSE: {
this.platform.log.debug('set Remote Key Pressed: PLAY_PAUSE');
this.sending([this.pressedButton('PLAY/PAUSE')]);
/* if (this.playBackState[0] === false) {
this.sending([this.pressedButton('PLAY')]);
}
else {
this.sending([this.pressedButton('PAUSE')]);
}
*/
break;
}
case this.platform.Characteristic.RemoteKey.INFORMATION: {
if (this.config.infoToMenu) {
this.platform.log.debug('set Remote Key Pressed: MENU');
this.sending([this.pressedButton('POP-UP MENU')]);
}
else {
this.platform.log.debug('set Remote Key Pressed: INFORMATION');
this.sending([this.pressedButton('INFO')]);
}
break;
}
}
callback(null);
});
//////////////////////////////////TV Service//////////////////////////////////////////////////////////////////////////
this.tvService
.setCharacteristic(this.platform.Characteristic.ActiveIdentifier, this.inputID);
this.tvService
.getCharacteristic(this.platform.Characteristic.ActiveIdentifier)
.on('set', (inputIdentifier, callback) => {
this.platform.log.debug('Active Identifier set to:', inputIdentifier);
this.inputID = inputIdentifier;
callback();
})
.on('get', (callback) => {
let currentValue = this.inputID;
this.platform.log.debug('Active Identifier set to:', currentValue);
callback(null, currentValue);
});
this.tvService
.getCharacteristic(this.platform.Characteristic.PowerModeSelection)
.on('set', (newValue, callback) => {
this.platform.log.debug('Requested Dune HD Settings ' + newValue);
if (this.playBackState[0] === false && this.playBackState[1] === false && this.playBackState[2] === false) {
this.sending([this.pressedButton('TOP MENU')]);
}
else {
this.sending([this.pressedButton('POP-UP MENU')]);
}
callback();
});
// Build all TV input source services from a declarative definition table.
this.buildInputSources();
/////Media State/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
this.tvService.getCharacteristic(this.platform.Characteristic.CurrentMediaState)
.on('get', (callback) => {
let currentValue = this.mediaState;
this.platform.log.debug('Current Playback State', currentValue);
callback(null, currentValue);
});
this.tvService.getCharacteristic(this.platform.Characteristic.TargetMediaState)
.on('get', (callback) => {
let currentValue = this.mediaState;
if (this.mediaState === 4) {
currentValue = 2;
}
this.platform.log.debug('Current Playback State', currentValue);
callback(null, currentValue);
})
.on('set', (value, callback) => {
if (value === 0) {
this.sending([this.pressedButton('PLAY')]);
}
else if (value === 1) {
this.sending([this.pressedButton('PAUSE')]);
}
else if (value === 2) {
this.sending([this.pressedButton('STOP')]);
}
this.platform.log.debug('Playback State set to:', value);
callback(null);
});
////Things to remove
this.tvService.getCharacteristic(this.platform.Characteristic.Brightness)
.on('get', (callback) => {
let currentValue = this.currentVolume;
callback(null, currentValue);
})
.on('set', (newValue, callback) => {
this.sending(["http://" + this.DUNEHD_IP + ":" + this.DUNEHD_PORT + "/cgi-bin/do?cmd=set_playback_state&volume=" + newValue + "&mute=0&result_syntax=json"]);
this.platform.log('Volume Value set to: ' + newValue);
callback(null);
});
this.tvService.getCharacteristic(this.platform.Characteristic.PictureMode)
.on('set', (newValue, callback) => {
if (newValue === 1) {
this.sending([this.pressedButton('VOLUME DOWN')]);
}
if (newValue === 0) {
this.sending([this.pressedButton('VOLUME UP')]);
}
this.platform.log('Volume Value moved by: ' + newValue);
callback(null);
});
//////
////////Volume services for the Dune HD/////////////////////////////////////////////////////////////////////////////////
this.speakerService = this.accessory.getService('Dune HD Volume Control') ||
this.accessory.addService(this.platform.Service.TelevisionSpeaker, 'Dune HD Volume Control', 'CataNicoGaTa-20');
this.speakerService
.setCharacteristic(this.platform.Characteristic.Active, this.platform.Characteristic.Active.ACTIVE)
.setCharacteristic(this.platform.Characteristic.VolumeControlType, this.platform.Characteristic.VolumeControlType.ABSOLUTE);
this.speakerService.getCharacteristic(this.platform.Characteristic.VolumeSelector)
.on('set', (newValue, callback) => {
if (newValue === 1) {
this.sending([this.pressedButton('VOLUME DOWN')]);
}
if (newValue === 0) {
this.sending([this.pressedButton('VOLUME UP')]);
}
this.platform.log('Volume Value moved by: ' + newValue);
callback(null);
});
this.speakerService.getCharacteristic(this.platform.Characteristic.Mute)
.on('get', (callback) => {
let currentValue = this.currentMuteState;
callback(null, currentValue);
})
.on('set', (newValue, callback) => {
if (newValue === true) {
this.sending(["http://" + this.DUNEHD_IP + ":" + this.DUNEHD_PORT + "/cgi-bin/do?cmd=set_playback_state_&mute=1&result_syntax=json"]);
this.platform.log('Volume Value set to: Mute');
}
if (newValue === false) {
this.sending(["http://" + this.DUNEHD_IP + ":" + this.DUNEHD_PORT + "/cgi-bin/do?cmd=set_playback_state&mute=0&result_syntax=json"]);
this.platform.log('Volume Value set to: Unmute');
}
callback(null);
});
this.speakerService.addCharacteristic(this.platform.Characteristic.Volume)
.on('get', (callback) => {
let currentValue = this.currentVolume;
callback(null, currentValue);
})
.on('set', (newValue, callback) => {
this.sending(["http://" + this.DUNEHD_IP + ":" + this.DUNEHD_PORT + "/cgi-bin/do?cmd=set_playback_state&volume=" + newValue + "&mute=0&result_syntax=json"]);
this.platform.log('Volume Value set to: ' + newValue);
callback(null);
});
this.tvService.addLinkedService(this.speakerService);
/////Volume and Video/Movie Controls/////////////////////////////////////////////////////////////////////
if (this.config.volume === true) {
this.buildVolumeControlService();
}
if (this.config.movieControl === true) {
this.buildMovieProgressService();
}
/////////////Addtional Services////////////////////////////////////////////////////////////////////////////////////
if (this.config.powerB === true) {
const powerSwitchServiceName = `${accessory.context.device.duneHDDisplayName} Power Switch`;
this.createStatefulSwitch({
propertyName: 'service',
serviceName: powerSwitchServiceName,
uniqueId: 'CataNicoGaTa-PWR-Dune',
onGet: this.getOn.bind(this),
onSet: this.setOn.bind(this),
setNameCharacteristic: true,
});
};
this.createStatefulSwitch({
propertyName: 'play',
serviceName: 'Play',
uniqueId: 'CataNicoGaTa-10',
onGet: this.playSwitchStateGet.bind(this),
onSet: this.playSwitchStateSet.bind(this),
});
this.createStatefulSwitch({
propertyName: 'pause',
serviceName: 'Pause',
uniqueId: 'CataNicoGaTa-11',
onGet: this.pauseSwitchStateGet.bind(this),
onSet: this.pauseSwitchStateSet.bind(this),
});
this.createStatefulSwitch({
propertyName: 'stop',
serviceName: 'Stop',
uniqueId: 'CataNicoGaTa-12',
onGet: this.stopSwitchStateGet.bind(this),
onSet: this.stopSwitchStateSet.bind(this),
});
///////////////////////////////////Input buttons//////////////////////////////////////////////////////////////////////////
this.buildStatelessSwitches();
if (this.config.remainMovieTimer) {
this.movieTimer = accessory.getService(this.platform.Service.Valve) || accessory.addService(this.platform.Service.Valve, 'Dune HD Movie Timer', 'Movie Timer');
this.movieTimer.setCharacteristic(this.platform.Characteristic.Name, 'Dune HD Movie Timer');
this.movieTimer.addOptionalCharacteristic(this.platform.Characteristic.ConfiguredName);
this.movieTimer.setCharacteristic(this.platform.Characteristic.ConfiguredName, 'Dune HD Movie Timer');
this.movieTimer.setCharacteristic(this.platform.Characteristic.ValveType, this.platform.Characteristic.ValveType.IRRIGATION);
this.movieTimer.getCharacteristic(this.platform.Characteristic.Active)
.on('get', (callback) => {
let currentValue = this.currentMovieProgressState ? 1 : 0
callback(null, currentValue);
})
.on('set', (value, callback) => {
callback(null);
});
this.movieTimer.setCharacteristic(this.platform.Characteristic.InUse, this.platform.Characteristic.InUse.NOT_IN_USE);
this.movieTimer.getCharacteristic(this.platform.Characteristic.RemainingDuration)
.on('get', (callback) => {
let currentValue = this.movieElapsed;
callback(null, currentValue);
})
.setProps({
maxValue: 86400 / 4, // 1 day
});
this.movieTimer.getCharacteristic(this.platform.Characteristic.SetDuration)
.on('get', (callback) => {
let currentValue = this.movieRemaining;
callback(null, currentValue);
})
.setProps({
maxValue: 86400 / 4, // 1 day
});
}
///////////////Clean up. Delete services not in used////////////////////////////////
this.cleanupDisabledServices();
//////////////////Connecting to Dune HD
// this.udpServer();
//syncing////////////////////////////////////////////////////////////////////////////////////////
setInterval(() => {
if (this.turnOffCommand === false && this.turnOnCommand === false) {
// Avoid overlapping poll requests when network/device responses are delayed.
if (this.pollInFlight !== true) {
this.sending([this.query('GET DEVICE INFO')]);
}
if (this.httpNotResponding >= this.reconnectionTry) {
if (this.turnOffAllUsed === false) {
this.turnOffAll();
this.turnOffAllUsed = true;
}
}
/*
this.platform.log('Updating');
this.platform.log(this.tvService.getCharacteristic(this.platform.Characteristic.Active).value);
this.platform.log(this.videoAudioTitle.getCharacteristic(this.platform.Characteristic.ConfiguredName).value);
this.platform.log(this.inputName);
this.platform.log(this.runtime.getCharacteristic(this.platform.Characteristic.ConfiguredName).value);
this.platform.log(this.mediaDuration);
this.platform.log(this.currentChaper.getCharacteristic(this.platform.Characteristic.ConfiguredName).value);
this.platform.log(this.mediaChapter);
this.platform.log(this.audioFormat.getCharacteristic(this.platform.Characteristic.ConfiguredName).value);
this.platform.log(this.mediaAudioFormat);
this.platform.log(this.audioLanguage.getCharacteristic(this.platform.Characteristic.ConfiguredName).value);
this.platform.log(this.language);
this.platform.log(this.pause.getCharacteristic(this.platform.Characteristic.On).value);
this.platform.log(this.playBackState);
*/
if (this.tvService.getCharacteristic(this.platform.Characteristic.Active).value !== this.powerStateTV) {
this.tvService.updateCharacteristic(this.platform.Characteristic.Active, this.powerStateTV);
}
if (this.play.getCharacteristic(this.platform.Characteristic.On).value !== this.playBackState[0]) {
this.play.updateCharacteristic(this.platform.Characteristic.On, this.playBackState[0]);
}
if (this.pause.getCharacteristic(this.platform.Characteristic.On).value !== this.playBackState[1]) {
this.pause.updateCharacteristic(this.platform.Characteristic.On, this.playBackState[1]);
}
if (this.stop.getCharacteristic(this.platform.Characteristic.On).value !== this.playBackState[2]) {
this.stop.updateCharacteristic(this.platform.Characteristic.On, this.playBackState[2]);
}
if (this.videoAudioTitle.getCharacteristic(this.platform.Characteristic.ConfiguredName).value !== this.inputName) {
this.platform.log.debug('Updating Title');
// this.videoAudioTitle.getCharacteristic(this.platform.Characteristic.ConfiguredName).updateValue(this.inputName);
this.videoAudioTitle.updateCharacteristic(this.platform.Characteristic.ConfiguredName, this.inputName);
}
if (this.runtime.getCharacteristic(this.platform.Characteristic.ConfiguredName).value !== this.mediaDuration) {
this.platform.log.debug('Updating Runtime');
this.runtime.updateCharacteristic(this.platform.Characteristic.ConfiguredName, this.mediaDuration);
//this.runtime.getCharacteristic(this.platform.Characteristic.ConfiguredName).updateValue(this.mediaDuration);
}
if (this.currentChaper.getCharacteristic(this.platform.Characteristic.ConfiguredName).value !== this.mediaChapter) {
this.platform.log.debug('Updating Current Chapter');
// this.currentChaper.getCharacteristic(this.platform.Characteristic.ConfiguredName).updateValue(this.mediaChapter);
this.currentChaper.updateCharacteristic(this.platform.Characteristic.ConfiguredName, this.mediaChapter);
}
if (this.audioFormat.getCharacteristic(this.platform.Characteristic.ConfiguredName).value !== this.mediaAudioFormat) {
this.platform.log.debug('Updating Audio Format');
// this.audioFormat.getCharacteristic(this.platform.Characteristic.ConfiguredName).updateValue(this.mediaAudioFormat);
this.audioFormat.updateCharacteristic(this.platform.Characteristic.ConfiguredName, this.mediaAudioFormat);
}
if (this.audioLanguage.getCharacteristic(this.platform.Characteristic.ConfiguredName).value !== this.language) {
this.platform.log.debug('Updating Language');
//this.audioLanguage.getCharacteristic(this.platform.Characteristic.ConfiguredName).updateValue(this.language);
this.audioLanguage.updateCharacteristic(this.platform.Characteristic.ConfiguredName, this.language);
}
if (this.videoAudioElapseTime.getCharacteristic(this.platform.Characteristic.ConfiguredName).value !== this.mediaInformation) {
this.platform.log.debug('Updating Video Information');
//this.videoAudioElapseTime.getCharacteristic(this.platform.Characteristic.ConfiguredName).updateValue(this.mediaInformation);
this.videoAudioElapseTime.updateCharacteristic(this.platform.Characteristic.ConfiguredName, this.mediaInformation);
}
}
else {
setTimeout(() => {
this.turnOffCommand = false;
this.turnOnCommand = false;
}, 3000);
}
}, this.config.pollingInterval);
setInterval(() => {
if (this.tvService.getCharacteristic(this.platform.Characteristic.Active).value === 1 && this.playBackState[0] === true) {
}
}, 120000);
}
// Declares all TV input sources in one place and builds/links each service from a definition object.
buildDualModeRangeService({
serviceName,
lightPropertyName,
fanPropertyName,
lightUniqueId,
fanUniqueId,
stateGetter,
onStateSet,
valueGetter,
onValueSet,
setNameCharacteristic = false,
}) {
const usesFanMode = this.config.changeDimmersToFan === true;
const propertyName = usesFanMode ? fanPropertyName : lightPropertyName;
const serviceType = usesFanMode ? this.platform.Service.Fanv2 : this.platform.Service.Lightbulb;
const uniqueId = usesFanMode ? fanUniqueId : lightUniqueId;
const stateCharacteristic = usesFanMode ? this.platform.Characteristic.Active : this.platform.Characteristic.On;
const valueCharacteristic = usesFanMode ? this.platform.Characteristic.RotationSpeed : this.platform.Characteristic.Brightness;
const service = this.accessory.getService(serviceName)
|| this.accessory.addService(serviceType, serviceName, uniqueId);
if (setNameCharacteristic === true) {
service.setCharacteristic(this.platform.Characteristic.Name, serviceName);
}
service.addOptionalCharacteristic(this.platform.Characteristic.ConfiguredName);
service.setCharacteristic(this.platform.Characteristic.ConfiguredName, serviceName);
service.getCharacteristic(stateCharacteristic)
.on('get', (callback) => {
const currentState = stateGetter();
if (usesFanMode) {
callback(null, currentState === true ? 1 : 0);
return;
}
callback(null, currentState);
})
.on('set', (newValue, callback) => {
onStateSet(newValue, usesFanMode);
callback(null);
});
service.getCharacteristic(valueCharacteristic)
.on('get', (callback) => {
callback(null, valueGetter());
})
.on('set', (newValue, callback) => {
onValueSet(newValue, usesFanMode);
callback(null);
});
this[propertyName] = service;
return service;
}
buildInputSources() {
const currentShown = this.platform.Characteristic.CurrentVisibilityState.SHOWN;
const currentHidden = this.platform.Characteristic.CurrentVisibilityState.HIDDEN;
const targetShown = this.platform.Characteristic.TargetVisibilityState.SHOWN;
const targetHidden = this.platform.Characteristic.TargetVisibilityState.HIDDEN;
const showMediaDetails = this.showState ? currentShown : currentHidden;
const showMediaDetailsTarget = this.showState ? targetShown : targetHidden;
const inputSourceDefinitions = [
{
propertyName: 'videoAudioTitle',
serviceName: 'Media Title',
uniqueId: 'CataNicoGaTa-1003',
identifier: 1,
configuredName: () => this.inputName,
inputSourceType: this.platform.Characteristic.InputSourceType.APPLICATION,
currentVisibility: currentShown,
onGet: () => this.inputName,
logOnGet: true,
},
{
propertyName: 'runtime',
serviceName: 'Runtime',
uniqueId: 'CataNicoGaTa-1004',
identifier: 2,
configuredName: () => this.mediaDuration,
inputSourceType: this.platform.Characteristic.InputSourceType.HDMI,
currentVisibility: currentShown,
onGet: () => this.mediaDuration,
logOnGet: true,
},
{
propertyName: 'videoAudioElapseTime',
serviceName: 'Video Information',
uniqueId: 'CataNicoGaTa-1005',
identifier: 4,
configuredName: () => this.mediaInformation,
inputSourceType: this.platform.Characteristic.InputSourceType.HDMI,
targetVisibility: targetHidden,
currentVisibility: currentHidden,
onGet: () => this.mediaInformation,
logOnGet: true,
},
{
propertyName: 'currentChaper',
serviceName: 'Current Chapter',
uniqueId: 'CataNicoGaTa-4005',
identifier: 3,
configuredName: () => this.mediaChapter,
inputSourceType: this.platform.Characteristic.InputSourceType.HDMI,
targetVisibility: showMediaDetailsTarget,
currentVisibility: showMediaDetails,
onGet: () => this.mediaChapter,
logOnGet: true,
},
{
propertyName: 'audioFormat',
serviceName: 'Audio Format',
uniqueId: 'CataNicoGaTa-4006',
identifier: 5,
configuredName: () => this.mediaAudioFormat,
inputSourceType: this.platform.Characteristic.InputSourceType.HDMI,
targetVisibility: showMediaDetailsTarget,
currentVisibility: showMediaDetails,
onGet: () => this.mediaAudioFormat,
logOnGet: true,
},
{
propertyName: 'audioLanguage',
serviceName: 'Audio Language',
uniqueId: 'CataNicoGaTa-4007',
identifier: 6,
configuredName: () => this.language,
inputSourceType: this.platform.Characteristic.InputSourceType.HDMI,
targetVisibility: showMediaDetailsTarget,
currentVisibility: showMediaDetails,
onGet: () => this.language,
logOnGet: true,
},
];
for (const definition of inputSourceDefinitions) {
this.getOrCreateInputSource(definition);
}
}
buildMovieProgressService() {
this.buildDualModeRangeService({
serviceName: 'Media Progress',
lightPropertyName: 'movieControlL',
fanPropertyName: 'movieControlF',
lightUniqueId: 'CataNicoGaTa-301',
fanUniqueId: 'CataNicoGaTa-301F',
setNameCharacteristic: true,
stateGetter: () => this.currentMovieProgressState,
onStateSet: (newValue) => {
this.platform.log('Movie progress state set to: ' + newValue);
},
valueGetter: () => this.currentMovieProgress,
onValueSet: (newValue) => {
this.setMovieSeekPositionFromPercent(newValue);
this.platform.log('Movie progress set to: ' + newValue + '%');
},
});
}
buildStatelessSwitches() {
for (const definition of this.getStatelessSwitchConfigs()) {
if (this.config[definition.configKey] === true) {
this.createStatelessSwitch(definition);
}
}
}
buildVolumeControlService() {
this.buildDualModeRangeService({
serviceName: 'Dune HD Volume',
lightPropertyName: 'volumeDimmer',
fanPropertyName: 'volumeFan',
lightUniqueId: 'CataNicoGaT-98',
fanUniqueId: 'CataNicoGaT-98F',
stateGetter: () => this.currentVolumeSwitch,
onStateSet: (newValue, usesFanMode) => {
const shouldUnmute = usesFanMode ? newValue === 1 : newValue === true;
if (shouldUnmute) {
this.sending(["http://" + this.DUNEHD_IP + ":" + this.DUNEHD_PORT + "/cgi-bin/do?cmd=set_playback_state_&mute=0&result_syntax=json"]);
this.platform.log('Volume Value set to: Unmute');
return;
}
this.sending(["http://" + this.DUNEHD_IP + ":" + this.DUNEHD_PORT + "/cgi-bin/do?cmd=set_playback_state&mute=1&resul