yamaha-nodejs-soef
Version:
An API to control your YAMAHA Receiver written in nodejs
551 lines (452 loc) • 21.7 kB
JavaScript
var Promise = require("bluebird");
var xml2js = Promise.promisifyAll(require("xml2js"));
var request = Promise.promisify(require("request"));
Promise.promisifyAll(request);
//<YAMAHA_AV cmd="GET"><USB><List_Info>GetParam</List_Info></USB></YAMAHA_AV>
//<YAMAHA_AV cmd="GET"><USB><Play_Info>GetParam</Play_Info></USB></YAMAHA_AV>
function Yamaha() {}
function getZone(zone){
if (!zone) return "Main_Zone";
// replace numbers with zones, eg type "2" and it will change to Zone 2
if (zone.length == 1) {
zone = zone.replace("/^1", "Main_Zone");
zone = zone.replace("/^2", "Zone_2");
zone = zone.replace("/^3", "Zone_3");
zone = zone.replace("/^4", "Zone_4");
}
switch (zone) {
case 1:
zone = "Main_Zone";
break;
case 2: case 3: case 4:
zone = "Zone_"+zone;
}
return zone;
}
Yamaha.prototype.muteOn = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Volume><Mute>On</Mute></Volume></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.muteOff = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Volume><Mute>Off</Mute></Volume></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.stop = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Play_Control><Playback>Stop</Playback></Play_Control></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.pause = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Play_Control><Playback>Pause</Playback></Play_Control></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.play = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Play_Control><Playback>Play</Playback></Play_Control></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.skip = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Play_Control><Playback>Skip Fwd</Playback></Play_Control></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.rewind = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Play_Control><Playback>Skip Rev</Playback></Play_Control></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.powerOn = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Power_Control><Power>On</Power></Power_Control></'+getZone(zone)+'></YAMAHA_AV>'
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.powerOff = function(zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Power_Control><Power>Standby</Power></Power_Control></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setVolumeTo = function(to, zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Volume><Lvl><Val>'+to+'</Val><Exp>1</Exp><Unit>dB</Unit></Lvl></Volume></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setVolume = Yamaha.prototype.setVolumeTo;
Yamaha.prototype.volumeUp = function(by){
return this.adjustVolumeBy(by);
};
Yamaha.prototype.volumeDown= function(by){
return this.adjustVolumeBy(-by);
};
Yamaha.prototype.adjustVolumeBy = function(by){
if (typeof by == 'string' || by instanceof String) by = parseInt(by);
var self = this;
return self.getBasicInfo().then(function(basicInfo){
return self.setVolumeTo(basicInfo.getVolume()+by);
});
};
Yamaha.prototype.partyModeOn = function(to){
var command = '<YAMAHA_AV cmd="PUT"><System><Party_Mode><Mode>On</Mode></Party_Mode></System></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.partyModeOff = function(to){
var command = '<YAMAHA_AV cmd="PUT"><System><Party_Mode><Mode>Off</Mode></Party_Mode></System></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.partyModeUp = function(to){
// Increments all zones up equally
var command = '<YAMAHA_AV cmd="PUT"><System><Party_Mode><Volume><Lvl>Up</Lvl></Volume><</Party_Mode></System></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.partyModeDown = function(to){
// Increments all zones down equally
var command = '<YAMAHA_AV cmd="PUT"><System><Party_Mode><Volume><Lvl>Down</Lvl></Volume><</Party_Mode></System></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setMainInputTo = function(to){
return this.setInputTo(to, "Main_Zone");
};
Yamaha.prototype.setInputTo = function(to, zone){
var command = '<YAMAHA_AV cmd="PUT"><'+getZone(zone)+'><Input><Input_Sel>'+to+'</Input_Sel></Input></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Yamaha.prototype.sendCommand = function (command, zone) {
zone = getZone(zone);
var command = '<YAMAHA_AV cmd="PUT"><' + zone + '>' + command + '</'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setMute = function (to) {
return this.sendCommand('<Volume><Mute>' + (to ? "On" : "Off") + '</Mute></Volume>');
};
Yamaha.prototype.sendRcCode = function (code) { // 7C80 = Power on/off
if (typeof code == 'number') {
code = code.toString(16);
}
//DSZ-Z7: <System><Remote_Signal><Receive><Code>***</Code></Receive></Remote_Signal></System>
//RX-Vx7x: <System><Misc><Remote_Signal><Receive><Code>***</Code></Receive></Remote_Signal></Misc></System>
//var command = '<YAMAHA_AV cmd="PUT"><Main_Zone><Remote_Control><RC_Code>' + code + '</RC_Code></Remote_Control></Main_Zone></YAMAHA_AV>';
//var command = '<YAMAHA_AV cmd="PUT"><System><Misc><Remote_Signal><Receive><Code>' + code + '</Code></Receive></Remote_Signal></Misc></System></YAMAHA_AV>';
//var command = '<YAMAHA_AV cmd="PUT"><System><Remote_Signal><Receive><Code>' + code + '</Code></Receive></Remote_Signal></System></YAMAHA_AV>';
var command = '<YAMAHA_AV cmd="PUT"><System><Remote_Control><RC_Code>' + code + '</RC_Code></Remote_Control></System></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setPureDirect = function(bo){
return this.sendCommand('<Sound_Video><Pure_Direct><Mode>' + (bo ? 'On' : 'Off') + '</Mode></Pure_Direct></Sound_Video>');
};
Yamaha.prototype.setHDMIOutput = function(no, bo){
return this.sendCommand('<Sound_Video><HDMI><Output><OUT_' + no + '>' + (bo ? 'On' : 'Off') + '</OUT_' + no + '></Output></HDMI></Sound_Video>', 'System');
};
Yamaha.prototype.scene = function(no) {
//adapter.setState('scene', '', true);
return this.sendCommand('<Scene><Scene_Load>Scene ' + no + '</Scene_Load></Scene>');
};
Yamaha.prototype.power = function(bo, zone){
return this.sendCommand('<Power_Control><Power>' + (bo ? 'On' : 'Standby') + '</Power></Power_Control>', zone);
};
Yamaha.prototype.allZones = function(bo){
return this.sendCommand('<Power_Control><Power>' + (bo ? 'On' : 'Standby') + '</Power></Power_Control>', 'System');
};
Yamaha.prototype.sleep = function(val, zone){
if (val < 30) val = 'Off';
else if (val < 60) val = '30 min';
else if (val < 90) val = '60 min';
else if (val < 120) val = '90 min';
else val = '120 min';
return this.sendCommand('<Power_Control><Sleep>' + val + '</Sleep></Power_Control>', zone);
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Yamaha.prototype.setBassTo = function(to){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><Tone><Bass><Val>'+to+'</Val><Exp>1</Exp><Unit>dB</Unit></Bass></Tone></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setTrebleTo = function(to){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><Tone><Treble><Val>'+to+'</Val><Exp>1</Exp><Unit>dB</Unit></Treble></Tone></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setSubwooferTrimTo = function(to){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Volume><Subwoofer_Trim><Val>'+to+'</Val><Exp>1</Exp><Unit>dB</Unit></Subwoofer_Trim></Volume></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setDialogLiftTo = function(to){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><Dialogue_Adjust><Dialogue_Lift>'+to+'</Dialogue_Lift></Dialogue_Adjust></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.setDialogLevelTo = function(to){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><Dialogue_Adjust><Dialogue_Lvl>'+to+'</Dialogue_Lvl></Dialogue_Adjust></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.YPAOVolumeOn = function(){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><YPAO_Volume>Auto</YPAO_Volume></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.YPAOVolumeOff = function(){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><YPAO_Volume>Off</YPAO_Volume></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.extraBassOn = function(){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><Extra_Bass>Auto</Extra_Bass></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.extraBassOff = function(){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><Extra_Bass>Off</Extra_Bass></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.adaptiveDRCOn = function(){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><Adaptive_DRC>Auto</Adaptive_DRC></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.adaptiveDRCOff = function(){
var zone = getZone(); //only available in Main Zone
var command = '<YAMAHA_AV cmd="PUT"><'+zone+'><Sound_Video><Adaptive_DRC>Off</Adaptive_DRC></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.SendXMLToReceiver= function(xml){
var isPutCommand = xml.indexOf("cmd=\"PUT\"">=0);
var delay = isPutCommand? this.responseDelay*1000:0;
var req = {
method: 'POST',
uri: 'http://'+this.ip+'/YamahaRemoteControl/ctrl',
body:xml
};
if (this.requestTimeout) req.timeout = this.requestTimeout;
return this.dontCatchRequestErrors === true ?
request.postAsync(req).delay(delay).then(function(response) {
return response.body;
}): request.postAsync(req).delay(delay).then(function(response) {
return response.body;
}).catch(function(e) {
console.log(e);
});
// return request.postAsync(req).delay(delay).then(function(response) {
// return response.body;
// }).catch(function(e) {
// if (dontCatch) throw e;
// else console.log(e);
// });
};
Yamaha.prototype.getColor = function()
{
return "The receiver is blue";
};
Yamaha.prototype.isHeadphoneConnected = function(){
//checks if a Headphone is connected, returns "Connected" or "Not Connected"
//is not available via getBasicInfo, that's why an additional request is needed
//only available in Zone 1, this setting is readonly
var zone = getZone(1);
var command = '<YAMAHA_AV cmd="GET"><'+zone+'><Sound_Video><Headphone>GetParam</Headphone></Sound_Video></'+zone+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command).then(xml2js.parseStringAsync).then(function(info){
try {
return info.YAMAHA_AV[zone][0].Sound_Video[0].Headphone[0];
}
catch (e) {
return "Not Available"; //if the Receiver has no Headphone Connector
}
});
}
Yamaha.prototype.getBasicInfo = function(zone){
var command = '<YAMAHA_AV cmd="GET"><'+getZone(zone)+'><Basic_Status>GetParam</Basic_Status></'+getZone(zone)+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command).then(xml2js.parseStringAsync).then(function(info){
return enrichBasicStatus(info, zone);
});
};
function enrichBasicStatus(basicStatus, zone){
var zone = getZone(zone);
basicStatus.getVolume = function(){
return parseInt(basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Volume[0].Lvl[0].Val[0]);
};
basicStatus.isMuted = function(){
return basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Volume[0].Mute[0] !== "Off";
};
basicStatus.isOn = function(){
return basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Power_Control[0].Power[0] === "On";
};
basicStatus.isOff = function(){
return !basicStatus.isOn();
};
basicStatus.getCurrentInput = function(){
return basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Input[0].Input_Sel[0];
};
basicStatus.isPartyModeEnabled = function(){
return basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Party_Info[0] === "On";
};
//the following properties are only available in Main Zone
basicStatus.isPureDirectEnabled = function(){
try {
return basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Sound_Video[0].Pure_Direct[0].Mode[0] === "On";
} catch (e) {
return 'Not Available';
}
};
basicStatus.getBass = function(){
try {
return parseInt(basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Sound_Video[0].Tone[0].Bass[0].Val[0]);
} catch (e) {
return 0;
}
};
basicStatus.getTreble = function(){
try {
return parseInt(basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Sound_Video[0].Tone[0].Treble[0].Val[0]);
} catch (e) {
return 0;
}
};
basicStatus.getSubwooferTrim = function(){
try {
return parseInt(basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Volume[0].Subwoofer_Trim[0].Val[0]);
} catch (e) {
return 0;
}
};
basicStatus.getDialogueLift = function(){
try {
return parseInt(basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Sound_Video[0].Dialogue_Adjust[0].Dialogue_Lift[0]);
} catch (e) {
return 0;
}
};
basicStatus.getDialogueLevel = function(){
try {
return parseInt(basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Sound_Video[0].Dialogue_Adjust[0].Dialogue_Lvl[0]);
} catch (e) {
return 0;
}
};
basicStatus.isYPAOVolumeEnabled = function(){
//values 'Off' or 'Auto'
try {
return basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Sound_Video[0].YPAO_Volume[0] !== 'Off';
} catch (e) {
return false;
}
};
basicStatus.isExtraBassEnabled = function(){
//values 'Off' or 'Auto'
try {
return basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Sound_Video[0].Extra_Bass[0] !== 'Off';
} catch (e) {
return false;
}
};
basicStatus.isAdaptiveDRCEnabled = function(){
//values 'Off' or 'Auto'
try {
return basicStatus.YAMAHA_AV[zone][0].Basic_Status[0].Sound_Video[0].Adaptive_DRC[0] !== 'Off';
} catch (e) {
return false;
}
};
return basicStatus;
}
// Add direct functions for basic info
function addBasicInfoWrapper(basicInfo){
Yamaha.prototype[basicInfo] = function(zone){
return this.getBasicInfo(zone).then(function(result){
return result[basicInfo]();
});
};
}
//TODO: no list, take properties of basicStatus object
var basicInfos = ["getVolume", "isMuted", "isOn", "isOff", "getCurrentInput","isPartyModeEnabled", "isPureDirectEnabled", "getBass", "getTreble", "getSubwooferTrim", "getDialogueLift", "getDialogueLevel", "isYPAOVolumeEnabled", "isExtraBassEnabled", "isAdaptiveDRCEnabled"];
for (var i = 0; i < basicInfos.length; i++) {
var basicInfo = basicInfos[i];
addBasicInfoWrapper(basicInfo);
}
Yamaha.prototype.getSystemConfig = function(){
var command = '<YAMAHA_AV cmd="GET"><System><Config>GetParam</Config></System></YAMAHA_AV>';
return this.SendXMLToReceiver(command).then(xml2js.parseStringAsync);
};
Yamaha.prototype.getAvailableInputs = function(){
return this.getSystemConfig().then(function(info){
var inputs = [];
var inputsXML = info.YAMAHA_AV.System[0].Config[0].Name[0].Input[0];
for (var prop in inputsXML) {
inputs.push(inputsXML[prop][0]);
}
return inputs;
});
};
Yamaha.prototype.selectListItem = function(listname, number){
var command = '<YAMAHA_AV cmd="PUT"><'+listname+'><List_Control><Direct_Sel>Line_'+number+'</Direct_Sel></List_Control></'+listname+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.getList = function(name){
var command = '<YAMAHA_AV cmd="GET"><'+name+'><List_Info>GetParam</List_Info></'+name+'></YAMAHA_AV>';
return this.SendXMLToReceiver(command).then(xml2js.parseStringAsync).then(function(info){
enrichListInfo(info, name);
return info;
});
};
function enrichListInfo(listInfo, listname){
listInfo.hasSelectableItems = function(){
return listInfo.YAMAHA_AV[listname][0].List_Info[0].Current_List[0].Line_1[0].Attribute[0] !== "Unselectable";
};
listInfo.isReady = function(){
return !listInfo.isBusy() && listInfo.hasSelectableItems();
};
listInfo.isBusy = function(){
return listInfo.YAMAHA_AV[listname][0].List_Info[0].Menu_Status[0] === "Busy";
};
listInfo.getMenuLayer = function(){
return listInfo.YAMAHA_AV[listname][0].List_Info[0].Menu_Layer[0];
};
listInfo.getMenuName = function(){
return listInfo.YAMAHA_AV[listname][0].List_Info[0].Menu_Name[0];
};
listInfo.getList = function(){
var list = listInfo.YAMAHA_AV[listname][0].List_Info[0].Menu_Name[0];
};
}
Yamaha.prototype.isMenuReady = function(name){
var self = this;
return self.getList(name).then(function(result){
return result.isReady();
});
};
Yamaha.prototype.whenMenuReady = function(name){
var self = this;
return self.when("isMenuReady",name, true);
};
Yamaha.prototype.when = function(YamahaCall, parameter, expectedReturnValue, tries){
var self = this;
tries = tries || 0;
return this[YamahaCall](parameter).then(function(result) {
console.log('Polling...');
if (result == expectedReturnValue) {
return true;
} else if (tries > 40) {
return Promise.reject("Timeout");
} else {
return Promise.delay(self.pollingDelay).then(function(){
return self.when(YamahaCall, parameter, expectedReturnValue, tries+1);
});
}
});
};
Yamaha.prototype.selectUSBListItem = function(number){
return this.selectListItem("USB", number);
};
Yamaha.prototype.selectWebRadioListItem = function(number){
return this.selectListItem("NET_RADIO", number);
};
Yamaha.prototype.selectTunerPreset = function(number){
var command = '<YAMAHA_AV cmd="PUT"><Tuner><Play_Control><Preset><Preset_Sel>'+number+'</Preset_Sel></Preset></Play_Control></Tuner></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
Yamaha.prototype.selectTunerFrequency = function(band, frequency){
var unit = band == "FM" ? "MHz" : "KHz"
, exp = band == "FM" ? 2 : 0
, command = '<YAMAHA_AV cmd="PUT"><Tuner><Play_Control><Tuning><Band>'+band+'</Band><Freq><'+band+'><Val>'+frequency+'</Val><Exp>'+exp+'</Exp><Unit>'+unit+'</Unit></'+band+'></Freq></Tuning></Play_Control></Tuner></YAMAHA_AV>';
return this.SendXMLToReceiver(command);
};
//TODO: More XML CONVERT
Yamaha.prototype.getWebRadioList = function(){
return this.getList("NET_RADIO");
};
Yamaha.prototype.getUSBList = function(){
return this.getList("USB");
};
module.exports = Yamaha;