homebridge-musiccast-tv
Version:
Homebridge plugin for Yamaha MusicCast devices
1,183 lines (1,169 loc) • 44.4 kB
JavaScript
var Service, Characteristic;
const request = require('request');
const url = require('url');
module.exports = function(homebridge) {
Service = homebridge.hap.Service;
Characteristic = homebridge.hap.Characteristic;
homebridge.registerAccessory("homebridge-musiccast-tv", "MusicCastTV", MusicCastTV);
};
function MusicCastTV(log, config) {
this.log = log;
this.name = config["name"];
this.ip = config["ip"];
this.zone = config["zone"] || "main";
this.volumeFan = config["volumeFan"] || 0 ;
this.volumeName = config["volumeName"] || this.name + " speaker";
this.buttonBand = config["buttonBand"] || "fm";
this.buttonNumber = config["buttonNumber"];
this.buttonName = config["buttonName"] || this.name + " button";
this.model = config["model"] || config["modell"] || "MusicCast TV";
this.volume = config["volume"] || 0;
this.maxVol = config["maxVol"];
this.ActiveIdentifier = config["identifier"] || 1;
this.serial = config["serialNo"] || "123-456-789";
this.category = 34;
that = this;
request({
method: 'GET',
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/getStatus',
headers: {
'X-AppName': 'MusicCast/1.0',
'X-AppPort': '41100',
},
},
function (error, response, body) {
if (error) {
that.log.error(error.message);
}
that.log.debug("body: " + body)
if(body) {
att=JSON.parse(body);
that.volume = config["volume"] || att.volume;
that.maxVol = config["maxVol"] || att.max_volume;
that.log("volume: " + that.volume + " maxVol: " + that.maxVol);
tmpInput = that.getInputFromString(att.input);
that.log("Input: " + tmpInput);
if(tmpInput != "") {
if(tmpInput=="tuner") {
that.getBand();
} else{
that.ActiveIdentifier = config["identifier"] || that.info[tmpInput]["Identifier"];
}
}
}
});
this.inputs = config["inputs"] || {"airplay": "1. 'inputs' missing", "bluetooth": "2. in config.json", "spotify": "3. please modify"};
this.active = config["active"] || 0;
this.powerOnInput = config["powerOnInput"];
this.powerOnVolume = config["powerOnVolume"];
this.mute = 1;
//this.brightness = config["brightness"] || 100;
this.updateInterval = config["updateInterval"] || 1000;
this.version = require("./package.json").version;
this.features = {};
this.info = {"airplay": {"Identifier": 1, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "airplay"},
"line_cd": {"Identifier": 2, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "line_cd"},
"fm": {"Identifier": 3, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "fm"},
"am": {"Identifier": 4, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "am"},
"dab": {"Identifier": 5, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "dab"},
"server": {"Identifier": 6, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "server"},
"phono": {"Identifier": 7, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "phono"},
"usb": {"Identifier": 8, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "usb"},
"usb_dac": {"Identifier": 9, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "usb_dac"},
"bluetooth": {"Identifier": 10, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "bluetooth"},
"net_radio": {"Identifier": 11, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "net_radio"},
"line1": {"Identifier": 12, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "line1"},
"line2": {"Identifier": 13, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "line2"},
"line3": {"Identifier": 14, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "line3"},
"optical": {"Identifier": 15, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "optical"},
"optical1": {"Identifier": 16, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "optical1"},
"optical2": {"Identifier": 17, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "optical2"},
"coaxial": {"Identifier": 18, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "coaxial"},
"coaxial1": {"Identifier": 19, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "coaxial1"},
"coaxial2": {"Identifier": 20, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "coaxial2"},
"hdmi": {"Identifier": 21, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi"},
"hdmi1": {"Identifier": 22, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi1"},
"hdmi2": {"Identifier": 23, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi2"},
"hdmi3": {"Identifier": 24, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi3"},
"hdmi4": {"Identifier": 25, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi4"},
"hdmi5": {"Identifier": 26, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi5"},
"hdmi6": {"Identifier": 27, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi6"},
"hdmi7": {"Identifier": 28, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi7"},
"hdmi8": {"Identifier": 29, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "hdmi8"},
"aux": {"Identifier": 30, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "aux"},
"aux1": {"Identifier": 31, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "aux1"},
"aux2": {"Identifier": 32, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "aux2"},
"v_aux": {"Identifier": 33, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "v_aux"},
"av1": {"Identifier": 34, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "av1"},
"av2": {"Identifier": 35, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "av2"},
"av3": {"Identifier": 36, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "av3"},
"av4": {"Identifier": 37, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "av4"},
"av5": {"Identifier": 38, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "av5"},
"av6": {"Identifier": 39, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "av6"},
"av7": {"Identifier": 40, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "av7"},
"cd": {"Identifier": 41, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "cd"},
"tv": {"Identifier": 42, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "tv"},
"analog": {"Identifier": 43, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "analog"},
"multi_ch": {"Identifier": 44, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "multi_ch"},
"audio": {"Identifier": 45, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "audio"},
"audio1": {"Identifier": 46, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "audio1"},
"audio2": {"Identifier": 47, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "audio2"},
"audio3": {"Identifier": 48, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "audio3"},
"audio4": {"Identifier": 49, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "audio4"},
"audio_cd": {"Identifier": 50, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "audio_cd"},
"digital": {"Identifier": 51, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "digital"},
"digital1": {"Identifier": 52, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "digital1"},
"digital2": {"Identifier": 53, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "digital2"},
"bd_dvd": {"Identifier": 54, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "bd_dvd"},
//"": {"Identifier": 55, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": ""},
"mc_link": {"Identifier": 56, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "mc_link"},
"main_sync": {"Identifier": 57, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": ""},
"spotify": {"Identifier": 58, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "spotify"},
"amazon_music": {"Identifier": 59, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "amazon_music"},
"deezer": {"Identifier": 60, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "deezer"},
"napster": {"Identifier": 61, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "napster"},
"qobuz": {"Identifier": 62, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "qobuz"},
"juke": {"Identifier": 63, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "juke"},
"tidal": {"Identifier": 64, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "tidal"},
"pandora": {"Identifier": 65, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "pandora"},
"siriusxm": {"Identifier": 66, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "siriusxm"},
"radiko": {"Identifier": 67, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "radiko"},
"alexa": {"Identifier": 68, "CurrentVisibilityState": 0, "TargetVisibilityState": 0, "Command": "alexa"}};
this.log.debug(config);
for(var key in this.inputs) {
this.log.debug("updating name for " + key);
tmpInput = this.getInputFromString(key);
if(tmpInput != "") {
if(tmpInput == "tuner") {
this.log.error("tuner is not a valid Input, please select \"am\", \"fm\" or \"dab\" for valid tuner types");
} else{
this.info[tmpInput]["ConfiguredName"] = this.inputs[key];
}
}
}
this.log("Initialized '" + this.name + "'");
}
MusicCastTV.prototype = {
identify: function(callback) {
this.log("Identify MusicCast TV '" + this.name + "'");
callback();
},
getInputFromString: function(name) {
switch(name) {
case "tuner":
return "tuner";
case "airplay":
case "AirPlay":
return "airplay";
case "phono":
case "Phono":
return "phono";
case "line_cd":
case "LineCD":
return "line_cd";
case "line1":
case "Line1":
return "line1";
case "line2":
case "Line2":
return "line2";
case "line3":
case "Line3":
return "line3";
case "fm":
case "FM":
return "fm";
case "am":
case "AM":
return "am";
case "dab":
case "DAB":
return "dab";
case "net_radio":
case "NetRadio":
return "net_radio";
case "server":
case "Server":
return "server";
case "bluetooth":
case "Bluetooth":
return "bluetooth";
case "usb":
case "USB":
return "usb";
case "usb_dac":
case "USB_DAC":
case "USBDAC":
return "usb_dac";
case "optical":
case "Optical":
return "optical";
case "optical1":
case "Optical1":
return "optical1";
case "optical2":
case "Optical2":
return "optical2";
case "coaxial":
case "Coaxial":
return "coaxial";
case "coaxial1":
case "Coaxial1":
return "coaxial1";
case "coaxial2":
case "Coaxial2":
return "coaxial2";
case "hdmi":
case "HDMI":
return "hdmi";
case "hdmi1":
case "HDMI1":
return "hdmi1";
case "hdmi2":
case "HDMI2":
return "hdmi2";
case "hdmi3":
case "HDMI3":
return "hdmi3";
case "hdmi4":
case "HDMI4":
return "hdmi4";
case "hdmi5":
case "HDMI5":
return "hdmi5";
case "hdmi6":
case "HDMI6":
return "hdmi6";
case "hdmi7":
case "HDMI7":
return "hdmi7";
case "hdmi8":
case "HDMI8":
return "hdmi8";
case "aux":
case "AUX":
return "aux";
case "aux1":
case "AUX1":
return "aux1";
case "aux2":
case "AUX2":
return "aux2";
case "v_aux":
case "V_AUX":
return "v_aux";
case "av1":
case "AV1":
return "av1";
case "av2":
case "AV2":
return "av2";
case "av3":
case "AV3":
return "av3";
case "av4":
case "AV4":
return "av4";
case "av5":
case "AV5":
return "av5";
case "av6":
case "AV6":
return "av6";
case "av7":
case "AV7":
return "av7";
case "cd":
case "CD":
return "cd";
case "tv":
case "TV":
return "tv";
case "analog":
case "Analog":
return "analog";
case "multi_ch":
case "MultiCh":
return "multi_ch";
case "audio":
return "audio";
case "audio1":
return "audio1";
case "audio2":
return "audio2";
case "audio3":
return "audio3";
case "audio4":
return "audio4";
case "audio_cd":
case "audiocd":
return "audio_cd";
case "digital":
return "digital";
case "digital1":
return "digital1";
case "digital2":
return "digital2";
case "bd_dvd":
case "bddvd":
return "bd_dvd";
case "mc_link":
return "mc_link";
case "main_sync":
case "sync":
return "main_sync";
case "spotify":
case "Spotify":
return "spotify";
case "amazon_music":
case "Amazon":
return "amazon_music";
case "deezer":
case "Deezer":
return "deezer";
case "napster":
case "Napster":
return "napster";
case "qobuz":
case "Qobuz":
return "qobuz";
case "juke":
case "Juke":
return "juke";
case "tidal":
case "Tidal":
return "tidal";
case "pandora":
case "Pandora":
return "pandora";
case "siriusxm":
case "Siriusxm":
case "SiriusXM":
return "siriusxm";
case "radiko":
return "radiko";
case "alexa":
case "Alexa":
return "alexa";
default:
this.log("input " + name + " not found");
return "";
}
},
getInputService: function(name) {
var tmpInputService = new Service.InputSource(name, name);
tmpInputService.setCharacteristic(Characteristic.Identifier, this.info[name]["Identifier"]);
tmpInputService.setCharacteristic(Characteristic.ConfiguredName, this.info[name]["ConfiguredName"]);
tmpInputService.setCharacteristic(Characteristic.IsConfigured, Characteristic.IsConfigured.CONFIGURED);
tmpInputService.setCharacteristic(Characteristic.CurrentVisibilityState, 0);
tmpInputService.getCharacteristic(Characteristic.CurrentVisibilityState).on('get', (callback) => {
this.log.debug("get CurrentVisibilityState of " + name + ": " + this.info[name]['CurrentVisibilityState']);
callback(null, this.info[name]['CurrentVisibilityState']);
}); //0=SHOWN;1=HIDDEN
tmpInputService.getCharacteristic(Characteristic.TargetVisibilityState).on('get', (callback) => {
this.log.debug('get TargetVisibilityState of ' + name + ": " + this.info[name]['TargetVisibilityState']);
callback(null, this.info[name]['TargetVisibilityState']);
});
tmpInputService.getCharacteristic(Characteristic.TargetVisibilityState).on('set', (value, callback) => {
this.info[name]['TargetVisibilityState'] = value;
this.log('Target Visibility State to ' + value + " " + this.info[name]['ConfiguredName']);
this.info[name]['CurrentVisibilityState'] = value;
callback();
});
return tmpInputService;
},
getBand: function() {
that = this;
request({
method: 'GET',
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/tuner/getPlayInfo',
headers: {
'X-AppName': 'MusicCast/1.0',
'X-AppPort': '41100',
},
},
function (error, response, body) {
if (error) {
that.log.debug('getBand error: ' + error.message);
return error;
} else if(body) {
that.log.debug("getBand body: " + body)
att = JSON.parse(body);
tmpInput = that.getInputFromString(att.band);
that.log.debug("Input: " + tmpInput);
if(tmpInput != "") {
that.ActiveIdentifier = that.info[tmpInput]["Identifier"];
that.TelevisionService.getCharacteristic(Characteristic.ActiveIdentifier)
.updateValue(that.ActiveIdentifier);
}
}
});
},
getHttpInput: function() {
this.tmp="";
that = this;
request({
method: 'GET',
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/getStatus',
headers: {
'X-AppName': 'MusicCast/1.0',
'X-AppPort': '41100',
},
},
function (error, response, body) {
if (error) {
that.log.debug('getHttpInput error: ' + error.message);
that.tmp = "error";
return error;
} else if(body) {
//that.log.debug("HttpInput body: " + body)
att = JSON.parse(body);
that.active = (att.power=='on');
that.volume = att.volume;
that.maxVol = att.max_volume;
//that.log.debug("volume: " + that.volume + " maxVol: " + that.maxVol);
tmpInput = that.getInputFromString(att.input);
if(tmpInput != "") {
if(tmpInput=="tuner") {
that.getBand();
} else{
//that.log.debug("Input: " + tmpInput);
that.ActiveIdentifier = that.info[tmpInput]["Identifier"];
that.TelevisionService.getCharacteristic(Characteristic.Active)
.updateValue(that.active);
that.TelevisionService.getCharacteristic(Characteristic.ActiveIdentifier)
.updateValue(that.ActiveIdentifier);
}
}
that.tmp = "updated";
} else{
that.log(error + "; body: " + body)
}
});
},
getActive: function(callback) {
this.tmp = "";
const that = this;
this.log.debug("get Active of " + this.name + ": " + this.active);
request({
method: 'GET',
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/getStatus',
headers: {
'X-AppName': 'MusicCast/1.0',
'X-AppPort': '41100',
},
},
function (error, response, body) {
if (error) {
that.log.error('getActive error: ' + error.message);
that.tmp = "error";
//return callback(error);
that.active=0;
that.TelevisionService
.getCharacteristic(Characteristic.Active)
.updateValue(0);
} else{
att=JSON.parse(body);
that.log.debug('HTTP getStatus result: ' + att.power);
that.active = (att.power=='on');
that.TelevisionService.getCharacteristic(Characteristic.Active)
.updateValue((att.power=='on'));
that.tmp = "success";
that.TelevisionService
.getCharacteristic(Characteristic.Active)
.updateValue(that.active);
//return callback(null, (att.power=='on'));
}
});
callback(null, this.active);
},
setActive: function(value, callback) {
const that = this;
this.active = value;
request({
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/setPower?power=' + (value ? 'on' : 'standby'),
method: 'GET',
body: ""
},
function (error, response) {
if (error) {
that.log.debug('http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/setPower?power=' + (value ? 'on' : 'standby'));
that.log.error('setActive error: ' + error.message);
return error;
}
});
this.log("Active to " + value);
if(value&&(this.powerOnInput||this.powerOnVolume)) { // missing: filter for state change
if(this.powerOnInput&&this.powerOnVolume) {
tmpInput = this.getInputFromString(this.powerOnInput);
this.log("powerOnInput: " + tmpInput + "; powerOnVolume: " + this.powerOnVolume);
this.setActiveIdentifier(this.info[tmpInput]["Identifier"], function() {}); //turn on powerOnInput
that.TelevisionService
.getCharacteristic(Characteristic.ActiveIdentifier)
.updateValue(this.info[tmpInput]["Identifier"]);
this.setVolume(this.powerOnVolume, callback);
//turn on both, one callback
}else if(this.powerOnInput) {
tmpInput = this.getInputFromString(this.powerOnInput);
this.log("powerOnInput: " + tmpInput);
this.setActiveIdentifier(this.info[tmpInput]["Identifier"], callback); //turn on powerOnInput
that.TelevisionService
.getCharacteristic(Characteristic.ActiveIdentifier)
.updateValue(this.info[tmpInput]["Identifier"]);
}else if(this.powerOnVolume) {
this.log("powerOnVolume: " + this.powerOnVolume);
this.setVolume(this.powerOnVolume, callback);
}
} else{
callback();
}
},
getActiveIdentifier: function(callback) {
this.getHttpInput();
setTimeout(() => {
this.TelevisionService
.getCharacteristic(Characteristic.ActiveIdentifier)
.updateValue(this.ActiveIdentifier);
}, this.updateInterval);
this.log("get Active Identifier: " + this.ActiveIdentifier);
callback(null, this.ActiveIdentifier);
},
setActiveIdentifier: function(value, callback) {
const that = this;
for(var key in this.info) {
if (this.info[key]["Identifier"] == value) {
var newInput = this.info[key]["Command"];
var tmpInput = newInput;
this.log("Switch to " + value + ": " + newInput);
}
}
if (tmpInput=="am" || tmpInput=="fm" || tmpInput=="dab") {
newInput = "tuner";
}
this.log.debug("ActiveIdentifier to " + value);
request({
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/setInput?input=' + newInput,
method: 'GET',
body: ""
},
function (error, response) {
if (error) {
that.log.debug('http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/setInput?input=' + newInput);
that.log.error(error.message);
return callback(error);
}
});
if (tmpInput=="am" || tmpInput=="fm" || tmpInput=="dab") {
request({
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/tuner/setBand?band=' + tmpInput,
method: 'GET',
body: ""
},
function (error, response) {
if (error) {
that.log.debug('http://' + this.ip + '/YamahaExtendedControl/v1/tuner/setBand?band=' + tmpInput);
that.log.error(error.message);
return callback(error);
}
});
}
this.ActiveIdentifier = value;
callback();
},
getButton: function(callback) {
this.log.debug("get Button: always 0");
callback(null, 0);
},
setButton: function(value, callback) {
this.log("Button: band " + this.buttonBand + " to " + this.buttonNumber);
request({
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/netusb/recallPreset?zone=' + this.zone + '&band=' + this.buttonBand + '&num=' + this.buttonNumber,
method: 'GET',
body: ""
},
function (error, response) {
if (error) {
that.log.debug('http://' + that.ip + '/YamahaExtendedControl/v1/tuner/recallPreset');
that.log.error(error.message);
// return callback(error);
} else{
that.log.debug('button activated');
}
});
callback();
},
getMute: function(callback) {
this.log.debug("get Mute: " + this.mute);
callback(null, this.mute);
},
setMute: function(value, callback) {
this.mute = value;
this.log("Mute to " + value);
callback();
},
remoteKeyPress: function(value, callback) {
switch (value) {
case 4:
this.log("remoteKeyPress UP");
this.setVolumeSelector(0, callback);
break;
case 5:
this.log("remoteKeyPress DOWN");
this.setVolumeSelector(1, callback);
break;
case 6:
this.log("remoteKeyPress LEFT");
return callback();
case 7:
this.log("remoteKeyPress RIGHT");
return callback();
case 8:
this.log("remoteKeyPress OK");
return callback();
case 9:
this.log("remoteKeyPress BACK");
return callback();
case 11:
this.log("remoteKeyPress Play/Pause");
//CurrentMediaState und TargetMediaState verändern
//0=PLAY;1=PAUSE;2=STOP
/*if (this.CurrentMediaState == 0) {
this.setTargetMediaState(1, callback);
//this.TargetMediaState = 1;
}
if (this.CurrentMediaState == 1) {
this.setTargetMediaState(0, callback);
//this.TargetMediaState = 0;
}*/
return callback();
case 15:
this.log("remoteKeyPress i");
return callback();
default:
this.log("remoteKeyPress " + value);
return callback();
}
},
getFakeVolume: function(callback) {
tmp = this.getHttpInput();
volume = ((this.volume*100)/this.maxVol); //turns a range between 0 and maxVolume into 0-100
if(isNaN(volume)) {
volume = 0;//filter NaN
}
this.log.debug("get FakeVolume: " + volume + " real: " + this.volume);
callback(null, volume);
},
setFakeVolume: function(value, callback) {
volume = ((value*this.maxVol)/100); //turns value between 0 and 100 into value between 0 and maxVolume
this.log.debug("set FakeVolume: " + value + " real: " + volume);
this.setVolume(volume, callback);
},
getVolume: function(callback) {
tmp = this.getHttpInput();
this.log.debug("get Volume: " + this.volume);
callback(null, this.volume);
},
setVolume: function(value, callback) {
const that = this;
value = Math.trunc(value); //cast to integer
if (value<0 || this.maxVol<value) {
this.log("Volume must be between 0 and " + this.maxVol + " requested: " + value);
callback();
return;
}
request({
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/setVolume?volume=' + value,
method: 'GET',
body: ""
},
function (error, response) {
if (error) {
that.log.debug('http://' + this.ip + '/YamahaExtendedControl/v1/' + this.zone + '/setVolume?volume=' + value);
that.log.error('setVolume error: ' + error.message);
return error;
}
})
this.volume = value;
this.log("set Volume: " + value);
if (value == 0) {
this.mute = 1;
} else {
this.mute = 0;
}
callback();
},
setVolumeSelector: function(value, callback) {
//this.getHttpInput();
this.log.debug("VolumeSelector: " + value + ", current Volume: " + this.volume);
if (value == 0) {
this.setVolume(this.volume+1, callback);
//setTimeout(this.setVolume, 1000, this.volume+1, callback);
}else if (value == 1){
this.setVolume(this.volume-1, callback);
}
},
getServices: function() {
let informationService = new Service.AccessoryInformation();
informationService
.setCharacteristic(Characteristic.Manufacturer, "homebridge-musiccast-tv")
.setCharacteristic(Characteristic.Model, this.model)
.setCharacteristic(Characteristic.SerialNumber, this.serial)
.setCharacteristic(Characteristic.FirmwareRevision, this.version);
this.informationService = informationService;
ServiceList = [];
ServiceList.push(informationService);
const that = this;
request({
url: 'http://' + this.ip + '/YamahaExtendedControl/v1/system/getFeatures',
method: 'GET',
headers: {
'X-AppName': 'MusicCast/1.0',
'X-AppPort': '41100',
}
},
function (error, response, body) {
if (error) {
that.log.error('getServices error: ' + error.message);
} else {
that.features=JSON.parse(body);
that.log.debug("func_list: " + JSON.stringify(that.features.system.func_list) +
", zone_num: " + JSON.stringify(that.features.system.zone_num));
that.log.debug("zone: " + JSON.stringify(that.features.zone));
}
});
let TelevisionService = new Service.Television(this.name);
TelevisionService
.setCharacteristic(Characteristic.ConfiguredName, this.name);
TelevisionService
.setCharacteristic(Characteristic.SleepDiscoveryMode, 1);
TelevisionService
.getCharacteristic(Characteristic.Active)
.on('get', this.getActive.bind(this))
.on('set', this.setActive.bind(this));
TelevisionService
.getCharacteristic(Characteristic.ActiveIdentifier)
.on('get', this.getActiveIdentifier.bind(this))
.on('set', this.setActiveIdentifier.bind(this));
TelevisionService
.getCharacteristic(Characteristic.RemoteKey)
.on('set', this.remoteKeyPress.bind(this));
setInterval(() => {
this.getHttpInput();
TelevisionService.getCharacteristic(Characteristic.Active)
.updateValue(this.active);
TelevisionService.getCharacteristic(Characteristic.ActiveIdentifier)
.updateValue(this.ActiveIdentifier);
}, this.updateInterval);
/*TelevisionService
.getCharacteristic(Characteristic.PowerModeSelection)//used to send a command that opens setting on TV
.on('set', this.setPowerModeSelection.bind(this));//0=Show Menu
TelevisionService
.getCharacteristic(Characteristic.CurrentMediaState)
.on('get', this.getCurrentMediaState.bind(this));
TelevisionService
.getCharacteristic(Characteristic.TargetMediaState)
.on('get', this.getTargetMediaState.bind(this))
.on('set', this.setTargetMediaState.bind(this));
setInterval(() => {
TelevisionService.getCharacteristic(Characteristic.CurrentMediaState)
.updateValue(this.CurrentMediaState);
}, this.updateInterval);*/
//TelevisionService.category=this.category;
this.TelevisionService = TelevisionService;
ServiceList.push(TelevisionService);
let TelevisionSpeakerService = new Service.TelevisionSpeaker(this.name + 'SpeakerService');
TelevisionSpeakerService
.setCharacteristic(Characteristic.Active, Characteristic.Active.ACTIVE)
.setCharacteristic(Characteristic.VolumeControlType, 3);
//0 NONE; 1 RELATIVE; 2 RELATIVE_WITH_CURRENT; 3 ABSOLUTE;
TelevisionSpeakerService
.getCharacteristic(Characteristic.VolumeSelector)//0 INCREMENT; 1 DECREMENT
.on('set', this.setVolumeSelector.bind(this));
TelevisionSpeakerService
.getCharacteristic(Characteristic.Mute) //not triggered via home app
.on('get', this.getMute.bind(this))
.on('set', this.setMute.bind(this));
TelevisionSpeakerService
.getCharacteristic(Characteristic.Volume) //not triggered via home app
.on('get', this.getFakeVolume.bind(this))
.on('set', this.setFakeVolume.bind(this));
TelevisionService.addLinkedService(TelevisionSpeakerService);
this.TelevisionSpeakerService = TelevisionSpeakerService;
ServiceList.push(TelevisionSpeakerService);
if(this.volumeFan) {
TelevisionFanService = new Service.Fan(this.volumeName);
TelevisionFanService
.getCharacteristic(Characteristic.On)
.on('get', this.getActive.bind(this));
TelevisionFanService
.getCharacteristic(Characteristic.RotationSpeed)
.on('get', this.getFakeVolume.bind(this))
.on('set', this.setFakeVolume.bind(this));
TelevisionService.addLinkedService(TelevisionFanService);
this.TelevisionFanService = TelevisionFanService;
ServiceList.push(TelevisionFanService);
}
if(this.buttonNumber) {
TelevisionButtonService = new Service.Switch(this.buttonName);
TelevisionButtonService
.getCharacteristic(Characteristic.On)
.on('get', this.getButton.bind(this))
.on('set', this.setButton.bind(this));
TelevisionService.addLinkedService(TelevisionButtonService);
this.TelevisionButtonService = TelevisionButtonService;
ServiceList.push(TelevisionButtonService);
}
for(var key in this.inputs) {
this.log.debug("processing input " + key);
tmpInput = this.getInputFromString(key);
switch (tmpInput) {
case "airplay":
this.airplayService = this.getInputService("airplay");
TelevisionService.addLinkedService(this.airplayService);
ServiceList.push(this.airplayService);
break;
case "phono":
this.phonoService = this.getInputService("phono");
TelevisionService.addLinkedService(this.phonoService);
ServiceList.push(this.phonoService);
break;
case "line_cd":
this.line_cdService = this.getInputService("line_cd");
TelevisionService.addLinkedService(this.line_cdService);
ServiceList.push(this.line_cdService);
break;
case "line1":
this.line1Service = this.getInputService("line1");
TelevisionService.addLinkedService(this.line1Service);
ServiceList.push(this.line1Service);
break;
case "line2":
this.line2Service = this.getInputService("line2");
TelevisionService.addLinkedService(this.line2Service);
ServiceList.push(this.line2Service);
break;
case "line3":
this.line3Service = this.getInputService("line3");
TelevisionService.addLinkedService(this.line3Service);
ServiceList.push(this.line3Service);
break;
case "fm":
this.fmService = this.getInputService("fm");
TelevisionService.addLinkedService(this.fmService);
ServiceList.push(this.fmService);
break;
case "am":
this.amService = this.getInputService("am");
TelevisionService.addLinkedService(this.amService);
ServiceList.push(this.amService);
break;
case "dab":
this.dabService = this.getInputService("dab");
TelevisionService.addLinkedService(this.dabService);
ServiceList.push(this.dabService);
break;
case "net_radio":
this.net_radioService = this.getInputService("net_radio");
TelevisionService.addLinkedService(this.net_radioService);
ServiceList.push(this.net_radioService);
break;
case "server":
this.serverService = this.getInputService("server");
TelevisionService.addLinkedService(this.serverService);
ServiceList.push(this.serverService);
break;
case "bluetooth":
this.bluetoothService = this.getInputService("bluetooth");
TelevisionService.addLinkedService(this.bluetoothService);
ServiceList.push(this.bluetoothService);
break;
case "usb":
this.usbService = this.getInputService("usb");
TelevisionService.addLinkedService(this.usbService);
ServiceList.push(this.usbService);
break;
case "usb_dac":
this.usb_dacService = this.getInputService("usb_dac");
TelevisionService.addLinkedService(this.usb_dacService);
ServiceList.push(this.usb_dacService);
break;
case "optical":
this.opticalService = this.getInputService("optical");
TelevisionService.addLinkedService(this.opticalService);
ServiceList.push(this.opticalService);
break;
case "optical1":
this.optical1Service = this.getInputService("optical1");
TelevisionService.addLinkedService(this.optical1Service);
ServiceList.push(this.optical1Service);
break;
case "optical2":
this.optical2Service = this.getInputService("optical2");
TelevisionService.addLinkedService(this.optical2Service);
ServiceList.push(this.optical2Service);
break;
case "coaxial":
this.coaxialService = this.getInputService("coaxial");
TelevisionService.addLinkedService(this.coaxialService);
ServiceList.push(this.coaxialService);
break;
case "coaxial1":
this.coaxial1Service = this.getInputService("coaxial1");
TelevisionService.addLinkedService(this.coaxial1Service);
ServiceList.push(this.coaxial1Service);
break;
case "coaxial2":
this.coaxial2Service = this.getInputService("coaxial2");
TelevisionService.addLinkedService(this.coaxial2Service);
ServiceList.push(this.coaxial2Service);
break;
case "hdmi":
this.hdmiService = this.getInputService("hdmi");
TelevisionService.addLinkedService(this.hdmiService);
ServiceList.push(this.hdmiService);
break;
case "hdmi1":
this.hdmi1Service = this.getInputService("hdmi1");
TelevisionService.addLinkedService(this.hdmi1Service);
ServiceList.push(this.hdmi1Service);
break;
case "hdmi2":
this.hdmi2Service = this.getInputService("hdmi2");
TelevisionService.addLinkedService(this.hdmi2Service);
ServiceList.push(this.hdmi2Service);
break;
case "hdmi3":
this.hdmi3Service = this.getInputService("hdmi3");
TelevisionService.addLinkedService(this.hdmi3Service);
ServiceList.push(this.hdmi3Service);
break;
case "hdmi4":
this.hdmi4Service = this.getInputService("hdmi4");
TelevisionService.addLinkedService(this.hdmi4Service);
ServiceList.push(this.hdmi4Service);
break;
case "hdmi5":
this.hdmi5Service = this.getInputService("hdmi5");
TelevisionService.addLinkedService(this.hdmi5Service);
ServiceList.push(this.hdmi5Service);
break;
case "hdmi6":
this.hdmi6Service = this.getInputService("hdmi6");
TelevisionService.addLinkedService(this.hdmi6Service);
ServiceList.push(this.hdmi6Service);
break;
case "hdmi7":
this.hdmi7Service = this.getInputService("hdmi7");
TelevisionService.addLinkedService(this.hdmi7Service);
ServiceList.push(this.hdmi7Service);
break;
case "hdmi8":
this.hdmi8Service = this.getInputService("hdmi8");
TelevisionService.addLinkedService(this.hdmi8Service);
ServiceList.push(this.hdmi8Service);
break;
case "aux":
this.auxService = this.getInputService("aux");
TelevisionService.addLinkedService(this.auxService);
ServiceList.push(this.auxService);
break;
case "aux1":
this.aux1Service = this.getInputService("aux1");
TelevisionService.addLinkedService(this.aux1Service);
ServiceList.push(this.aux1Service);
break;
case "aux2":
this.aux2Service = this.getInputService("aux2");
TelevisionService.addLinkedService(this.aux2Service);
ServiceList.push(this.aux2Service);
break;
case "v_aux":
this.v_auxService = this.getInputService("v_aux");
TelevisionService.addLinkedService(this.v_auxService);
ServiceList.push(this.v_auxService);
break;
case "av1":
this.av1Service = this.getInputService("av1");
TelevisionService.addLinkedService(this.av1Service);
ServiceList.push(this.av1Service);
break;
case "av2":
this.av2Service = this.getInputService("av2");
TelevisionService.addLinkedService(this.av2Service);
ServiceList.push(this.av2Service);
break;
case "av3":
this.av3Service = this.getInputService("av3");
TelevisionService.addLinkedService(this.av3Service);
ServiceList.push(this.av3Service);
break;
case "av4":
this.av4Service = this.getInputService("av4");
TelevisionService.addLinkedService(this.av4Service);
ServiceList.push(this.av4Service);
break;
case "av5":
this.av5Service = this.getInputService("av5");
TelevisionService.addLinkedService(this.av5Service);
ServiceList.push(this.av5Service);
break;
case "av6":
this.av6Service = this.getInputService("av6");
TelevisionService.addLinkedService(this.av6Service);
ServiceList.push(this.av6Service);
break;
case "av7":
this.av7Service = this.getInputService("av7");
TelevisionService.addLinkedService(this.av7Service);
ServiceList.push(this.av7Service);
break;
case "cd":
this.cdService = this.getInputService("cd");
TelevisionService.addLinkedService(this.cdService);
ServiceList.push(this.cdService);
break;
case "tv":
this.tvService = this.getInputService("tv");
TelevisionService.addLinkedService(this.tvService);
ServiceList.push(this.tvService);
break;
case "analog":
this.analogService = this.getInputService("analog");
TelevisionService.addLinkedService(this.analogService);
ServiceList.push(this.analogService);
break;
case "multi_ch":
this.multi_chService = this.getInputService("multi_ch");
TelevisionService.addLinkedService(this.multi_chService);
ServiceList.push(this.multi_chService);
break;
case "audio":
this.audioService = this.getInputService("audio");
TelevisionService.addLinkedService(this.audioService);
ServiceList.push(this.audioService);
break;
case "audio1":
this.audio1Service = this.getInputService("audio1");
TelevisionService.addLinkedService(this.audio1Service);
ServiceList.push(this.audio1Service);
break;
case "audio2":
this.audio2Service = this.getInputService("audio2");
TelevisionService.addLinkedService(this.audio2Service);
ServiceList.push(this.audio2Service);
break;
case "audio3":
this.audio3Service = this.getInputService("audio3");
TelevisionService.addLinkedService(this.audio3Service);
ServiceList.push(this.audio3Service);
break;
case "audio4":
this.audio4Service = this.getInputService("audio4");
TelevisionService.addLinkedService(this.audio4Service);
ServiceList.push(this.audio4Service);
break;
case "audio_cd":
this.audio_cdService = this.getInputService("audio_cd");
TelevisionService.addLinkedService(this.audio_cdService);
ServiceList.push(this.audio_cdService);
break;
case "digital":
this.digitalService = this.getInputService("digital");
TelevisionService.addLinkedService(this.digitalService);
ServiceList.push(this.digitalService);
break;
case "digital1":
this.digital1Service = this.getInputService("digital1");
TelevisionService.addLinkedService(this.digital1Service);
ServiceList.push(this.digital1Service);
break;
case "digital2":
this.digital2Service = this.getInputService("digital2");
TelevisionService.addLinkedService(this.digital2Service);
ServiceList.push(this.digital2Service);
break;
case "bd_dvd":
this.bd_dvdService = this.getInputService("bd_dvd");
TelevisionService.addLinkedService(this.bd_dvdService);
ServiceList.push(this.bd_dvdService);
break;
case "mc_link":
this.mc_linkService = this.getInputService("mc_link");
TelevisionService.addLinkedService(this.mc_linkService);
ServiceList.push(this.mc_linkService);
break;
/*case "main_sync":
this.main_syncService = this.getInputService("main_sync");
TelevisionService.addLinkedService(this.main_syncService);
ServiceList.push(this.main_syncService);
break;*/
case "spotify":
this.spotifyService = this.getInputService("spotify");
TelevisionService.addLinkedService(this.spotifyService);
ServiceList.push(this.spotifyService);
break;
case "amazon_music":
this.amazon_musicService = this.getInputService("amazon_music");
TelevisionService.addLinkedService(this.amazon_musicService);
ServiceList.push(this.amazon_musicService);
break;
case "deezer":
this.deezerService = this.getInputService("deezer");
TelevisionService.addLinkedService(this.deezerService);
ServiceList.push(this.deezerService);
break;
case "napster":
this.napsterService = this.getInputService("napster");
TelevisionService.addLinkedService(this.napsterService);
ServiceList.push(this.napsterService);
break;
case "qobuz":
this.qobuzService = this.getInputService("qobuz");
TelevisionService.addLinkedService(this.qobuzService);
ServiceList.push(this.qobuzService);
break;
case "juke":
this.jukeService = this.getInputService("juke");
TelevisionService.addLinkedService(this.jukeService);
ServiceList.push(this.jukeService);
break;
case "tidal":
this.tidalService = this.getInputService("tidal");
TelevisionService.addLinkedService(this.tidalService);
ServiceList.push(this.tidalService);
break;
case "pandora":
this.pandoraService = this.getInputService("pandora");
TelevisionService.addLinkedService(this.pandoraService);
ServiceList.push(this.pandoraService);
break;
case "sirusxm":
this.siriusxmService = this.getInputService("siriusxm");
TelevisionService.addLinkedService(this.siriusxmService);
ServiceList.push(this.siriusxmService);
break;
case "radiko":
this.radikoService = this.getInputService("radiko");
TelevisionService.addLinkedService(this.radikoService);
ServiceList.push(this.radikoService);
break;
case "alexa":
this.alexaService = this.getInputService("alexa");
TelevisionService.addLinkedService(this.alexaService);
ServiceList.push(this.alexaService);
break;
default:
this.log.error("input " + key + " not found");
this.log("please file a feature request and include this log");
this.log("zone features: " + this.features.zone);
}
}
/*eval("InputService" + i + ".setCharacteristic(Characteristic.InputSourceType, this.inputs[key]['InputSourceType'])");
//0=OTHER;1=HOME_SCREEN;2=TUNER;3=HDMI; 4=COMPOSITE_VIDEO;5=S_VIDEO;
//6=COMPONENT_VIDEO;7=DVI;8=AIRPLAY;9=USB;10=APPLICATION;
eval("InputService" + i + ".setCharacteristic(Characteristic.InputDeviceType, this.inputs[key]['InputDeviceType'])");
//0=OTHER;1=TV;2=RECORDING;3=TUNER;4=PLAYBACK;5=AUDIO_SYSTEM;
};*/
return ServiceList;
}
}