/// Read out volumio via rest api var request = require('request'); var querystring = require('querystring'); var pollingInterval = 500//in ms var Folder = 'javascript.0.Volumio.Player.Volumio_Player_' // var Volumios = ["Studio"] //["rStream","workStream","kitchenStream","flurStream"] //muss in beiden Skripten identisch sein var Volumios_IPs = ["210"] //["82","58","48","72"] //192.168.0 wird dann im Skript hart gesetzt -> ggf. abändern! Reihenfolge der IPs muss mit den drüber definierten Namen übereinstimmen! var getStates_States_with_RawValues = ['samplerate','bitdepth','title','bitrate'] var getStates_States_wo_RawValues = ['status','artist','album','albumart','uri','trackType','duration','seek','service','channels','consume','volume','dbVolume','mute','disableVolumeControl','stream','volatile', 'updatedb','trackType','random','position','repeatSingle','repeat'] var getStates_States = getStates_States_wo_RawValues.concat(getStates_States_with_RawValues) //States erstellen // ToDo -> states nur erstellen wenn sie nicht exisitieren for (ID_Volumio in Volumios){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroom',false ,{"role": "indicator", "name": "indicates player in multiroom mode", "type": "boolean", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomPlaying',false ,{"role": "indicator", "name": "indicates player in multiroom mode", "type": "boolean", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomSender', false,{"role": "indicator", "name": "indicates player in Sender multiroom mode", "type": "boolean", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceiver', false,{"role": "indicator", "name": "indicates playerstate in Receiver multiroom mode", "type": "boolean", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceivingFromName', "",{"role": "text", "name": "indicates multiroom mode Mother", "type": "string", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceivingFromID', 99,{"role": "value", "name": "indicates multiroom mode Mother", "type": "number", "read": true, "write": true }) for (Stati in getStates_States){ var field = getStates_States[Stati] if(field == "updatedb"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "indicator", "name": "updatedb", "type": "boolean", "read": true, "write": true }) } if(field == "trackType"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "text", "name": "Type of current track (flac/mp3/acc/..)", "type": "string", "read": true, "write": true }) } if(field == "random"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "indicator", "name": "Repeat playlist activated", "type": "boolean", "read": true, "write": true }) } if(field == "repeatSingle"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.state", "name": "Repeat current track activated", "type": "boolean", "read": true, "write": true }) } if(field == "position"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.track", "name": "Position in playlist of current track-start at 0", "type": "number", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'Corrected', {"role": "media.track", "name": "Position in playlist of current track-start at 1", "type": "number", "read": true, "write": true }) } if(field == "repeat"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.mode.repeat", "name": "Repeat playlist activated", "type": "boolean", "read": true, "write": true }) } if(field == "status"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.state", "name": "Playback status", "type": "string", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'LastValue', {"role": "media.state", "name": "Playback status Last Value", "type": "string", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'IncomingCall', {"role": "media.state", "name": "Playback status Call is incoming", "type": "string", "read": true, "write": true }) } if(field == "title"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.title", "name": "Title of current track", "type": "string", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'Raw', {"role": "media.title", "name": "Title of current track", "type": "string", "read": true, "write": true }) } if(field == "artist"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.artist", "name": "Artist of current track", "type": "string", "read": true, "write": true }) } if(field == "album"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.album", "name": "Album of current track", "type": "string", "read": true, "write": true }) } if(field == "albumart"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.cover", "name": "Cover url of current track", "type": "string", "read": true, "write": true }) } if(field == "uri"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.url", "name": "rl of current track", "type": "string", "read": true, "write": true }) } if(field == "trackType"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "text", "name": "Type of current track (flac/mp3/acc/..)", "type": "string", "read": true, "write": true }) } if(field == "seek"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.seek","unit":"ms", "name": "Seek position of current track", "type": "number", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_percent', {"role": "media.seek","unit":"%", "name": "Seek position of current track", "type": "number", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_s', {"role": "media.seek","unit":"s", "name": "Seek position of current track", "type": "number", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_mmss', {"role": "text", "name": "Seek position of current track", "type": "string", "read": true, "write": true }) } if(field == "duration"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.duration","unit":"s", "name": "Duration of current track", "type": "number", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_ms', {"role": "media.duration","unit":"ms", "name": "Duration of current track", "type": "number", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_mmss', {"role": "text", "name": "Duration of current track", "type": "string", "read": true, "write": true }) } if(field == "samplerate"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "string", "name": "samplerate of current track", "type": "string", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'Raw', {"role": "media.samplerate", "name": "raw samplerate of current track ", "type": "number", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'Raw2', {"role": "media.samplerate", "name": "raw samplerate of current track ", "type": "string", "read": true, "write": true }) } if(field == "bitrate"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "string", "name": "bitrate of current track", "type": "string", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'Raw', {"role": "media.bitrate", "name": "raw bitrate of current track ","unit":'kbps', "type": "number", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'Raw2', {"role": "media.bitrate", "name": "raw bitrate of current track ", "type": "string", "read": true, "write": true }) } if(field == "bitdepth"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "text", "name": "bitdepth of current track", "type": "string", "read": true, "write": true }) createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'Raw', {"role": "media.bitdepth", "name": "raw bitdepth of current track", "unit": "bit", "type": "number", "read": true, "write": true }) } if(field == "channels"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "value", "name": "channels of current track", "type": "number", "read": true, "write": true }) } if(field == "consume"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "indicator", "name": "consume", "type": "boolean", "read": true, "write": true }) } if(field == "volume"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "level.volume", "name": "volume in percent", "unit": "%","type": "number", "read": true, "write": true }) } if(field == "dbVolume"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "level.volume", "name": "volume in dB", "unit": "dB","type": "number", "read": true, "write": true }) } if(field == "mute"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "media.mute", "name": "muted status", "type": "boolean", "read": true, "write": true }) } if(field == "disableVolumeControl"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "indicator", "name": "Shuffle playmode activated", "type": "boolean", "read": true, "write": true }) } if(field == "stream"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "text", "name": "stream", "type": "string", "read": true, "write": true }) } if(field == "volatile"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "indicator", "name": "volatile", "type": "boolean", "read": true, "write": true }) } if(field == "service"){ createState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field, {"role": "text", "name": "service where playback is from", "type": "string", "read": true, "write": true }) } } } //------------ get Informations per intervall ------------------------- var timer var intervall clearTimeout(timer) clearInterval(intervall) timer = setTimeout(function () { timer = null; intervall= null; clearTimeout(timer); clearInterval(intervall); intervall = setInterval(getVolumioStates, pollingInterval, Volumios_IPs ) }, 1000 * 3); //10 sekunden dieder motion sensor noch braucht zum zurücksetzen sind aufzuaddieren //------------ get Informations per intervall ------------------------- //------------------ create listener for raw values ------------------- var getStates_States_with_RawValuesWithAddListeners = getStates_States_with_RawValues.concat(['status','channels']) for (ID_Volumio in Volumios_IPs){ for (Stati in getStates_States_with_RawValuesWithAddListeners){ on({id: Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + getStates_States_with_RawValuesWithAddListeners[Stati], change: 'any'}, function (obj) { var value = obj.state.val; var oldValue = obj.oldState.val var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) //untescheidung nach kHz mHz! if (StateName == 'title'){ splitted = value.split(' ') firstIsNumber = typeof(parseFloat(splitted[0])) if(typeof(parseFloat(splitted[0])) == "number"){ firstIsNumber = true }else{firstIsNumber=false} if(splitted[1] == "-"){ secondStrich = true }else{secondStrich=false} if(firstIsNumber === true && secondStrich === true){ delete splitted[1] delete splitted[0] result = splitted.join(' ') }else{result = value} setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'Raw', result) }else if (StateName == 'status'){ var StatusOldValue = getState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName).val setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'LastValue',oldValue) }else if (StateName == 'channels'){ setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.Infos.Audio.Source_Channels', parseFloat(value)) }else if (StateName == 'bitrate'){ log(ID_Volumio_Verursacher + ": Receiving: " + getState(Folder+ID_Volumio_Verursacher+'.playbackInfo.multiroomReceiver').val) if(String(value).toLowerCase().includes('kbps')){ result = parseFloat(value) setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'Raw2', result + ' kbps') }else{result = 0 setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'Raw2', 'notAvailable') } }else if (StateName == 'bitdepth'){ var BitDepthTemp = parseFloat(value) result = BitDepthTemp var SampleRateTemp = getState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRate').val var ServiceTemp = getState(Folder + ID_Volumio_Verursacher + '.playbackInfo.service').val if((BitDepthTemp > 16 || SampleRateTemp > 48000) && ServiceTemp != 'multiroom' ){ setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.HiRes_Audio',true) }else{ setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.HiRes_Audio',false) } setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_bitdeepth', parseFloat(value)) if(value == 'notAvailable'){ setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_bitdeepthDisplay', 'notAvailable') }else{ setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_bitdeepthDisplay', String(value)) } }else if (StateName == 'samplerate'){ var SampleRateTemp = parseFloat(value) var BitDepthTemp = getState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_bitdeepth').val var ServiceTemp = getState(Folder + ID_Volumio_Verursacher + '.playbackInfo.service').val log("BitDepthTemp 2:" + BitDepthTemp) if((BitDepthTemp > 16 || SampleRateTemp > 48000) && ServiceTemp != 'multiroom'){ setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.HiRes_Audio',true) }else{setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.HiRes_Audio',false)} if(String(value).toLowerCase().includes('khz')){ result = parseFloat(value)*1000 setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'Raw2', result/1000 + ' kHz') setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRateDisplay', result/1000 + ' kHz') setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRate', result) } else if(String(value).toLowerCase().includes('mhz')){ result = parseFloat(value)*1000000 setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'Raw2', result/1000000 + ' MHz') setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRateDisplay', result/1000000 + ' MHz') setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRate', result) }else if(String(value).toLowerCase().includes('kbps')){ result = parseFloat(value) setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'Raw2', result + ' kbps') setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRateDisplay', result + ' kbps') setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRate', 0) }else if(value == null||value == 'null' ||value == 'undefined' || value == undefined||value == 'notAvailable'){ result = 0 setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'Raw2', 'notAvailable') setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRateDisplay', 'notAvailable') setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRate', 0) }else{result = parseFloat(value)} }else{ result = parseFloat(value) } if (StateName != 'service' && StateName != 'status' && StateName != 'channels'){ setState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + StateName + 'Raw', result) } }); } } //------------------ create listener for raw values ------------------- // ------------------ states for control ------------------------ var Buttons_Control = ['next','previous','play','pause','stop','mute','unmute','mute_toggle','PlayPause','PlayPause_controlFolder','volume_up','volume_down','removeAsReceiver','removeAllReceiver'] var VolumioAPIString1 = "http://" var VolumioAPIStringCommand = "/api/v1/commands/?cmd=" for (ID_Volumio in Volumios_IPs){ var FolderPlayer = Folder + String(parseInt(ID_Volumio)) var FolderControl = FolderPlayer + '.control' for (iter in Buttons_Control){ // console.log(iter) if (Buttons_Control[iter] == "VolumeControl_ID"){ createState(FolderControl+'.'+Buttons_Control[iter],false, {role:"value", type: "string",name: Buttons_Control[iter] }) setState(FolderControl+'.'+Buttons_Control[iter],false) }else if (Buttons_Control[iter] == "Volume"){ createState(FolderControl+'.'+Buttons_Control[iter],false, {role:"value", type: "number",name: Buttons_Control[iter] }) setState(FolderControl+'.'+Buttons_Control[iter],false) }else if (Buttons_Control[iter] == "removeAsReceiver"){ createState(FolderControl+'.'+Buttons_Control[iter],false, {role:"button", type: "boolean",name: 'Remove pi from multiroom if pi is a Receiver' }) setState(FolderControl+'.'+Buttons_Control[iter],false) }else if (Buttons_Control[iter] == "removeAllReceiver"){ createState(FolderControl+'.'+Buttons_Control[iter],false, {role:"button", type: "boolean",name: 'Remove all Receiver Pis from receiving' }) setState(FolderControl+'.'+Buttons_Control[iter],false) }else if (Buttons_Control[iter] == "PlayPause"){ createState(FolderPlayer+'.'+Buttons_Control[iter],false, {role:"button", type: "boolean",name: Buttons_Control[iter] + ' Toggle' }) setState(FolderPlayer+'.'+Buttons_Control[iter],false) } else{ createState(FolderControl+'.'+Buttons_Control[iter],false, {role:"button", type: "boolean",name: Buttons_Control[iter] }) setState(FolderControl+'.'+Buttons_Control[iter],false) } } on({id: FolderControl+'.'+Buttons_Control[0], change: 'ne'}, function (obj) { // next var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var ID_Multiroom_Temp = parseInt(getState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + 'multiroomReceivingFromID').val) if(ID_Multiroom_Temp != 99 && ID_Multiroom_Temp <= parseInt(Volumios.length)){ // sicherehits auf länge ID_Volumio_Verursacher = ID_Multiroom_Temp } if(value === true){ //do something var command = "next" var URL = VolumioAPIString1 + '192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[1], change: 'ne'}, function (obj) { // previous var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var ID_Multiroom_Temp = parseInt(getState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + 'multiroomReceivingFromID').val) if(ID_Multiroom_Temp != 99 && ID_Multiroom_Temp <= parseInt(Volumios.length)){ ID_Volumio_Verursacher = ID_Multiroom_Temp } if(value === true){ //do something var command = "prev" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[2], change: 'ne'}, function (obj) { // play var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var ID_Multiroom_Temp = parseInt(getState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + 'multiroomReceivingFromID').val) if(ID_Multiroom_Temp != 99 && ID_Multiroom_Temp <= parseInt(Volumios.length)){ ID_Volumio_Verursacher = ID_Multiroom_Temp } if(value === true){ //do something var command = "play" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[3], change: 'ne'}, function (obj) { // pause var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var ID_Multiroom_Temp = parseInt(getState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + 'multiroomReceivingFromID').val) if(ID_Multiroom_Temp != 99 && ID_Multiroom_Temp <= parseInt(Volumios.length)){ ID_Volumio_Verursacher = ID_Multiroom_Temp } if(value === true){ //do something var command = "pause" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[4], change: 'ne'}, function (obj) { // stop var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) if(value === true){ //do something var command = "stop" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[5], change: 'ne'}, function (obj) { // mute var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) if(value === true){ //do something var command = "volume&volume=mute" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[6], change: 'ne'}, function (obj) { // unmute var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) if(value === true){ //do something var command = "volume&volume=unmute" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[7], change: 'ne'}, function (obj) { // mute_toggle var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) if(value === true){ //do something var MuteStateTemp = getState(Folder + String(ID_Volumio_Verursacher) + '.playbackInfo.mute').val if (MuteStateTemp === false || MuteStateTemp == "false"){ //muten var command = "volume&volume=mute" }else if (MuteStateTemp === true || MuteStateTemp == "true"){ //unmuten var command = "volume&volume=unmute" } var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderPlayer+'.'+Buttons_Control[8], change: 'any'}, function (obj) { // PlayPause //ACHTUNG HIER ANDERER ORDNER IM LISTENER var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio_noSubfolder(obj.id,Volumios) // ACHTUNG HIER ANDERE FUNKTION, DA ICH IN ANDEREM ORDNER UNTERWEGS BIN var ID_Multiroom_Temp = parseInt(getState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + 'multiroomReceivingFromID').val) if(ID_Multiroom_Temp != 99 && ID_Multiroom_Temp <= parseInt(Volumios.length)){ // sicherehits auf länge ID_Volumio_Verursacher = ID_Multiroom_Temp } if(value === true){ //do something var command = "toggle" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command log(URL) httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[9], change: 'ne'}, function (obj) { // PlayPause_controlFolder var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var ID_Multiroom_Temp = parseInt(getState(Folder + String(parseInt(ID_Volumio_Verursacher)) + '.playbackInfo.' + 'multiroomReceivingFromID').val) if(ID_Multiroom_Temp != 99 && ID_Multiroom_Temp <= parseInt(Volumios.length)){ // sicherehits auf länge ID_Volumio_Verursacher = ID_Multiroom_Temp } if(value === true){ //do something setState(Folder + String(ID_Volumio_Verursacher) + '.PlayPause',true) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[10], change: 'ne'}, function (obj) { // volume_up var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) if(value === true){ //do something var command = "volume&volume=plus" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command log(URL) httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[11], change: 'ne'}, function (obj) { // volume_down var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) if(value === true){ //do something var command = "volume&volume=minus" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command log(URL) httpRequest_wo_return(URL) setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[12], change: 'ne'}, function (obj) { // removeAsReceiver var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var IsPiReceiving = getState(Folder + ID_Volumio_Verursacher + '.playbackInfo.multiroomReceiver').val if(value === true){ //do something if(IsPiReceiving){ var command = "stop" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command log(URL) httpRequest_wo_return(URL) } setState(Verursacher,false) } }); on({id: FolderControl+'.'+Buttons_Control[13], change: 'ne'}, function (obj) { // removeAllReceiver var value = obj.state.val; var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var ReceivingVolumios = getVolumiosReceiving([],true) if(value === true){ //do something for(PiToKill in ReceivingVolumios){ var command = "stop" var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ReceivingVolumios[PiToKill]] + VolumioAPIStringCommand + command log(URL) httpRequest_wo_return(URL) } setState(Verursacher,false) } }); on({id: Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + getStates_States[11] , change: 'ne'}, function (obj) { // volume (in folder playbackinfo) var value = obj.state.val; var oldValue = obj.oldState.val; if(value != oldValue){ var NewVolume = value var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var command = "volume&volume=" + parseInt(NewVolume) var URL = VolumioAPIString1 +'192.168.0.' + Volumios_IPs[ID_Volumio_Verursacher] + VolumioAPIStringCommand + command log(URL) httpRequest_wo_return(URL) } }); } // ------------------ states for control ------------------------ //set Resetz hiRes in multiroom verbund for (ID_Volumio in Volumios_IPs){ on({id: Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceiver', change: 'any'}, function (obj) { var value = obj.state.val; var oldValue = obj.oldState.val var Verursacher = obj.id; var StateName = getIDofState(obj.id) var ID_Volumio_Verursacher = getIDVolumio(obj.id,Volumios) var IsChildTemp = value var ServiceTemp = getState(Folder + ID_Volumio_Verursacher + '.playbackInfo.service').val var BitDepthTemp = getState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_bitdeepth').val var SampleRateTemp = getState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.Source_SampleRate').val log("BitDepthTemp 3:" + BitDepthTemp) log("IsChildTemp 3:" + IsChildTemp) //if((BitDepthTemp > 16 || SampleRateTemp > 44100) && IsChildTemp === false && ServiceTemp != 'multiroom'){//&& getState(Folder+ID_Volumio_Verursacher+'.playbackInfo.multiroomReceiver').val === false){ if((BitDepthTemp > 16 || SampleRateTemp > 48000) && IsChildTemp === false && ServiceTemp != 'multiroom'){//&& getState(Folder+ID_Volumio_Verursacher+'.playbackInfo.multiroomReceiver').val === false){ setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.HiRes_Audio',true) }else{ setState(Folder + ID_Volumio_Verursacher + '.Infos.Audio.HiRes_Audio',false) } }); } function extract(JSONvariable,fieldname) { return getAttr((function () { try {return JSON.parse(JSONvariable);} catch(e) {return {};}})(), fieldname) } function restapiRequest(ip,command,ID_Volumio) { //sendet ssh befehl an moodeaudio muss ich eigentlich auf zertifikat umstellen var url = 'http://' + ip + '/api/v1/' + command if(getState('ping.0.ioBroker.' + Volumios[ID_Volumio]).val + '.alive'){ try { require("request")(url, async function (error, response, result) { if(error != null){ if(String(error).includes('read ECONNRESET') || String(error).includes('connect EHOSTUNREACH 192.168.0.') || String(error).includes('connect ECONNREFUSED 192.168.0.')){ log("ERROR Volumio: " + error) return; } } // log(getStates_States) // log(ID_Volumio + 'is receiver ' + getState(Folder + ID_Volumio + '.playbackInfo.multiroomReceiver').val) if(command == "getState"){ for (Stati in getStates_States){ var field = getStates_States[Stati] // log(field) var value = extract(result,field) if (field == 'channels'){ } if (field == 'bitrate'){ // log("Bitrate: " + value) } if (field == 'position'){ setState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + 'Corrected', parseInt(value)+1) } if (field == 'seek'){ var TrackDurationTemp = parseFloat(getState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'duration').val ) var elapsed_sec = parseFloat(value)/1000 var elapsedPercent = Math.round(100*(elapsed_sec/TrackDurationTemp)* 100) * 0.01 var elapsedMM = parseInt(elapsed_sec/60) var elapsedSS = parseInt(elapsed_sec) - 60*elapsedMM var elapsedMM_string = String(elapsedMM) var elapsedSS_string = String(elapsedSS) if(elapsedMM_string.length == 1){elapsedMM_string = '0'+elapsedMM_string} if(elapsedSS_string.length == 1){elapsedSS_string = '0'+elapsedSS_string} var elapsedMMSS = elapsedMM_string + ':' + elapsedSS_string setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_s', elapsed_sec) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_percent', elapsedPercent) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_mmss', elapsedMMSS) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_percent',elapsedPercent) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_mmss',elapsedMMSS) } if (field == 'duration'){ var duration_sec = parseFloat(value) var duration_ms = duration_sec*1000 var durationMM = parseInt(duration_sec/60) var durationSS = parseInt(duration_sec) - 60*durationMM var durationMM_string = String(durationMM) var durationSS_string = String(durationSS) if(durationMM_string.length == 1){durationMM_string = '0'+durationMM_string} if(durationSS_string.length == 1){durationSS_string = '0'+durationSS_string} var durationMMSS = durationMM_string + ':' + durationSS_string setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_mmss', durationMMSS) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_ms',duration_ms) //nur setzen wenn es eine änderung gab setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field + '_mmss',durationMMSS) } if (field == 'albumart'){ try{ if(value.includes('http') === true){ var CoverURL = value }else{ var CoverURL = 'http://' + ip + value } setState(Folder + String(ID_Volumio) + '.Infos.Audio.CoverArt',CoverURL) }catch(e){} } if (field == 'service'){ //Service muss immer gesetzt werden! umd multiroom status zu erhalten // ------------------ Multiroom Handling v2 --------------------------------------- //erst mutter dann kinder herausfinden, kann im zweifel 2 sekunden dauern //funktioniert nur wenn ein multiroom verbund vorhanden ist, ansonsten kommt kp was raus var CurrentTrackOnCurrentPi = getState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'title').val var CurrentAlbumOnCurrentPi = getState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'album').val var CurrentServiceOnCurrentPi = getState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'service').val var CurrentStatusOnCurrentPi = getState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'status').val if(String(value).toLowerCase().includes('multiroom') == false){ // Fall 1: Sender //vergleichen ob ein anderer PI das gleiche abspielt und in multiroom betrieb ist, dann ist pi == mother var CurrentSender = '' var CurrentSenderID = parseInt(99) var CurrentReceiver = '' var CurrentReceiverID = parseInt(99) for (ID_VolumioSearch in Volumios){ if(ID_VolumioSearch != ID_Volumio){ var CurrentTrackOnOtherPi = getState(Folder + String(parseInt(ID_VolumioSearch)) + '.playbackInfo.' + 'title').val var CurrentAlbumOnOtherPi = getState(Folder + String(parseInt(ID_VolumioSearch)) + '.playbackInfo.' + 'album').val var CurrentServiceOnOtherPi = getState(Folder + String(parseInt(ID_VolumioSearch)) + '.playbackInfo.' + 'service').val var CurrentStatusOnOtherPi = getState(Folder + String(parseInt(ID_VolumioSearch)) + '.playbackInfo.' + 'status').val if (CurrentStatusOnCurrentPi == CurrentStatusOnOtherPi && CurrentTrackOnCurrentPi == CurrentTrackOnOtherPi && CurrentServiceOnOtherPi == 'multiroom'){ // == -> ID_Volumio = mother; ?? -> receiver CurrentSender = Volumios[ID_Volumio] CurrentSenderID = parseInt(ID_Volumio) CurrentReceiver = Volumios[ID_VolumioSearch] CurrentReceiverID = parseInt(ID_VolumioSearch) // log('CurrentServiceRefreshed: ' + Volumios[ID_Volumio]) //nochmals gegenprüfen ob son von möglichen müttern auch auf anderen wiedergegeben wird! //nur schreiben wenn sich was ändert!!!! und auch zurücksetzen setStateOnlyIfDifferent(Folder + String(parseInt(CurrentReceiverID)) + '.playbackInfo.' + 'multiroom',true) setStateOnlyIfDifferent(Folder + String(parseInt(CurrentSenderID)) + '.playbackInfo.' + 'multiroom',true) setStateOnlyIfDifferent(Folder + String(parseInt(CurrentSenderID)) + '.playbackInfo.' + 'multiroomSender',true) setStateOnlyIfDifferent(Folder + String(parseInt(CurrentReceiverID)) + '.playbackInfo.' + 'multiroomReceiver',true) setStateOnlyIfDifferent(Folder + String(parseInt(CurrentReceiverID)) + '.playbackInfo.' + 'multiroomReceivingFromID',CurrentSenderID) setStateOnlyIfDifferent(Folder + String(parseInt(CurrentReceiverID)) + '.playbackInfo.' + 'multiroomReceivingFromName',CurrentSender) //und in abfrage abfangen, dass diese infos nicht gesetzt werden wenn er receiver ist if(getState(Folder + String(parseInt(CurrentReceiverID)) + '.playbackInfo.' + 'status').val == 'play'){ setStateOnlyIfDifferent(Folder + String(parseInt(CurrentReceiverID)) + '.playbackInfo.' + 'multiroomPlaying', true) }else{ setStateOnlyIfDifferent(Folder + String(parseInt(CurrentReceiverID)) + '.playbackInfo.' + 'multiroomPlaying', false) } if(getState(Folder + String(parseInt(CurrentSenderID)) + '.playbackInfo.' + 'status').val == 'play'){ setStateOnlyIfDifferent(Folder + String(parseInt(CurrentSenderID)) + '.playbackInfo.' + 'multiroomPlaying', true) }else{ setStateOnlyIfDifferent(Folder + String(parseInt(CurrentSenderID)) + '.playbackInfo.' + 'multiroomPlaying', false) } }else{ } } } if(CurrentSender == '' || CurrentSenderID == parseInt(99)){ setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomSender', false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomPlaying', false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceiver',false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceiver',false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceiver',false) } if(CurrentReceiver == ''){} if(CurrentReceiverID == parseInt(99)){} }else if(String(value).toLowerCase().includes('multiroom')){ setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomSender',false) }else{ } var ID_ReceivingTemp = parseInt(getState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceivingFromID').val) if(ID_ReceivingTemp != 99 ){ var ID_ReceivingTempTitle = getState(Folder + String(ID_ReceivingTemp) + '.playbackInfo.' + 'title').val var ID_ReceivingTempStatus = getState(Folder + String(ID_ReceivingTemp) + '.playbackInfo.' + 'status').val }else{ var ID_ReceivingTempTitle = 'TempValue' var ID_ReceivingTempStatus = 'TempValue' } //wenn gleich multiroom aber pla state/titel ungleich motherid oder wenn state ungleich multiroom und PI ist kein Sender if(ID_ReceivingTemp != 99){ if(CurrentServiceOnCurrentPi == 'multiroom' && (CurrentTrackOnCurrentPi != ID_ReceivingTempTitle ||CurrentStatusOnCurrentPi != ID_ReceivingTempStatus)){ setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroom', false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomSender', false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomPlaying', false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceiver',false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceivingFromID',99) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceivingFromName','') } } if (CurrentServiceOnCurrentPi != 'multiroom' && ID_Volumio != CurrentSenderID && ID_Volumio != CurrentReceiverID){ setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroom',false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroom',false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceiver',false) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceivingFromID',99) setStateOnlyIfDifferent(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + 'multiroomReceivingFromName','') } // ------------------ Multiroom Handling v2 --------------------------------------- } // set default volume, e.g. after reboot if ((value == "" || value == undefined || value == "undefined") && (value!=0||value!="0")){ value = "notAvailable" //handling dass 0 nicht als null interpretiert wird.... if(field == 'volume'){ switch(parseInt(ID_Volumio)) { case 0: // rStream value = 20 break; case 1: // workStream value = 28 break; case 2: // kitchenStream value = 32 break; case 3: // flurStream value = 35 break; default: value = 20 // } } } // Handling wenn wert "notAvailable" und state ist typ number -> value = 0 statt "notAvailable" var TypeOfState = getObject(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field).common.type //logs hierfür in if weiter unten! sonst logt er bei jedem refresh if(TypeOfState == 'number' && value == 'notAvailable'){ // log('ERROR') value = 0 } if(TypeOfState == 'boolean' && value == 'notAvailable'){ // log('ERROR') value = false } if(TypeOfState == 'string' && (value === false || value === true)){ // log('ERROR') value = String(value) } //nur setzen wenn es eine änderung gab if(getState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field).val != value){ setState(Folder + String(parseInt(ID_Volumio)) + '.playbackInfo.' + field,value) if(field == 'stream'){ } } } } if(command == "getQueue"){ log(result) } if(command == "getzones"){ zones = extract(result,'zones') for (i in zones){ log(zones[i]) log(i) } log(result) } if(command == "collectionstats"){ log(result) } if(command == "pushNotificationUrls"){ log(result) } if(command == "ping"){ log(result) } if(command == "getSystemVersion"){ log(result) } if(command == "getSystemInfo"){ log(result) } }).on("error", function (e) { // returnValue = "ERROR" //console.error(e); }); return; } catch (e) { // returnValue = "ERROR"; //console.error(e); return; } } } function setStateOnlyIfDifferent(ObjectID,NewValue){ var CurrentValue = getState(ObjectID).val if(CurrentValue != NewValue){ setState(ObjectID,NewValue) } } function getIDVolumioForInfos(objID){ var PlayerName = objID.split(".")[objID.split('.').length-4].split('_') return PlayerName[PlayerName.length-1] } function getIDofState(objID){ return objID.split(".")[objID.split('.').length-1] } function getIDVolumio(objID){ var PlayerName = objID.split(".")[objID.split('.').length-3].split('_') return PlayerName[PlayerName.length-1] } function getIDVolumio_noSubfolder(objID){ var PlayerName = objID.split(".")[objID.split('.').length-2].split('_') return PlayerName[PlayerName.length-1] } function getVolumioStates(Volumios_IPs){ for (ID_Volumio in Volumios_IPs){ restapiRequest('192.168.0.' + Volumios_IPs[ID_Volumio],"getState",ID_Volumio) } } function httpRequest_wo_return(URL){ try { require("request")(URL).on("error", function (e) {console.error(e);}); } catch (e) { console.error(e); } }