[OBSOLETE] Denon Network AV Receivers

Sorry folks, I’ve upgraded my AVR and no longer have a Denon so is hard to support blindly. Plus the new Denon AVRs don’t use the same structure, so this DTH is becoming antiquated fast, if not obsolete already…

If anyone is interested in continuing to work on this, please PM or just step in and take over.

1 Like

How exciting! How awesome! Obsoleting a huge chunk of what works for the existing customer base… way to go, Samsung!!

The customizability is pretty much the reason I chose ST over the then-competition.
But before I get too bugged-out, let’s see how it plays out.

Just tried installing this for my AVR-X4400h. Got everything installed and updated the IP but the classic app force closes as soon as I click the device. Haven’t tried the new app.

As well I installed in the classic app, no problems but accessing does a force close on the app.

We don’t know what the new app is going to be when it launches because it’s not done yet. It will have to support custom DTH because most of the devices people use require them. It’s got more functionality than the current app which should allow developers to do even more with it. I don’t know why everyone is getting so down over something no one has seen yet cause it’s still being worked on.

I’ve written a smartapp and DTH for these HEOS receivers. It does automatic SSDP discovery. Currently it only controls main zone power/volume/source/media control stuff.

9 Likes

This works awesome! Thank you!

I can confirm flawless working with the AVR-X2400H

Thanks, good to know that!

like others original DH crashes with my Denon AVR-X3000 but ported it over to the Hubitat hub and works fine.
I control my Denon AVR-X3000 through my Harmony hub on SmartThings anyway.

1 Like

This works great, Thanks for the hard work.

I’m brand new to all this , but managed to add the device handler, and then the device. It seem correct, I used the instructions that andykn posted.

However when I try to run in it in Smarthings, All I see is this:


for about 2 seconds, followed by a another very brief screen that is completely white/blank. Then I get kicked back the My Home menu:

I updated the IP address and port to my AVR x4000 (which I can set to by either tapping setting in the ST mobile app before it auto closes or api.smarthings.com/device/list), but that had no effect.

Hey I know this post is from a while ago but did you ever have any luck? I’d love to control my Zone2 volume.

Thanks!

Sort of, but it ain’t pretty. Basically I created a new DTH with the zone 2 commands and then added another device using that DTH:

 *  	Denon Network Receiver 
 *    	Based on Denon/Marantz receiver by Kristopher Kubicki
 *    	SmartThings driver to connect your Denon Network Receiver to SmartThings
 *		Tested with AVR-S710W (game1 & game2 inputs are not available), AVR 1912

TESED DENON MODELS
    ModelId
	EnModelUnknown,		//(0)
	EnModelAVRX10,		//(1)
	EnModelAVRX20,		//(2)
	EnModelAVRX30,		//(3)
	EnModelAVRX40,		//(4)
	EnModelAVRX50,		//(5)
	EnModelAVRX70,		//(6)
	EnModelNR15,		//(7)
	EnModelNR16,		//(8)
	EnModelSR50,		//(9)
	EnModelSR60,		//(10)
	EnModelSR70,		//(11)
	EnModelAV77,		//(12)
	EnModelAV88,		//(13)
*/

metadata {
    definition (name: "Denon AVR Zone2", namespace: "SB", 
        author: "Bobby Dobrescu") {
        capability "Actuator"
        capability "Switch" 
        capability "Polling"
        capability "Switch Level"
        capability "Music Player" 
        
        attribute "mute", "string"
        attribute "input", "string"     
        attribute "cbl", "string"
        attribute "tv", "string"
		attribute "dvd", "string"
        attribute "cd", "string"
		attribute "mp", "string"
		attribute "bt", "string"
        attribute "z2cd", "string"
		attribute "game", "string"
		attribute "sMovie", "string"        
		attribute "sMusic", "string"          
		attribute "sPure", "string"        
		attribute "q1", "string"
		attribute "q2", "string"
		attribute "q3", "string"        
		attribute "q4", "string"          
		attribute "zone2", "string" 



        command "mute"
        command "unmute"
        command "toggleMute"
        command "inputSelect", ["string"]
        command "inputNext"
		command "cbl"
		command "tv"
		command "bd"
		command "dvd"
		command "mp"
        command "cd"
        command "z2cd"
		command "bt"
		command "game"
		command "sMovie"
		command "sMusic"
		command "sPure"
		command "q1"
		command "q2"
		command "q3"
		command "q4"
		command "sPure" 
		command "z2on"        
		command "z2off"        

        }


preferences {
    input("destIp", "text", title: "IP", description: "The device IP")
    input("destPort", "number", title: "Port", description: "The port you wish to connect", defaultValue: 80)
	input(title: "Denon AVR version: ${getVersionTxt()}" ,description: null, type : "paragraph")
}


    simulator {
        // TODO-: define status and reply messages here
    }

    //tiles {
	tiles(scale: 2) {
		multiAttributeTile(name:"multiAVR", type: "mediaPlayer", width: 6, height: 4) {
           tileAttribute("device.status", key: "PRIMARY_CONTROL") { 	            
            	attributeState ("paused", label: 'Paused', backgroundColor: "#53a7c0", defaultState: true)
				attributeState ("playing", label: 'Playing', backgroundColor: "#79b821")
        	}             
            tileAttribute("device.status", key: "MEDIA_STATUS") { 	            
            	attributeState "playing", label: '${name}', action:"switch.off"
                attributeState "paused", label: '${name}', action:"switch.on"
			}  
            tileAttribute ("device.level", key: "SLIDER_CONTROL") {
           		attributeState ("level", action:"setLevel")
                }       
            tileAttribute ("device.mute", key: "MEDIA_MUTED") {
            	attributeState("unmuted", action:"mute", nextState: "muted")
            	attributeState("muted", action:"unmute", nextState: "unmuted")
        	}
        }  
        controlTile("z2Control", "device.z2Level", "slider", height: 1, width: 3, inactiveLabel: false) {
            state "level", action:"setLevelz2", label:'Zone2 Volume'
        }
        standardTile("input7", "device.game", width: 2, height: 2, decoration: "flat"){
        	state "OFF", label: 'Chromecast', action: "game", icon:"st.Electronics.electronics5", backgroundColor: "#FFFFFF",nextState:"ON"   
            state "ON", label: 'Chromecast', action: "game", icon:"st.Electronics.electronics5", backgroundColor: "#53a7c0", nextState:"OFF"   
			} 
        standardTile("input1", "device.cbl", width: 2, height: 2, decoration: "flat"){     
            state "OFF", label: 'Cable', action: "cbl", icon:"st.Electronics.electronics3", backgroundColor: "#FFFFFF", nextState:"ON"
            state "ON", label: 'Cable', action: "cbl", icon:"st.Electronics.electronics3" , backgroundColor: "#53a7c0", nextState:"OFF"        
            }
        standardTile("input2", "device.tv", width: 2, height: 2, decoration: "flat"){
        	 state "OFF", label: 'TV', action: "tv", icon:"st.Electronics.electronics18", backgroundColor:"#FFFFFF",nextState:"ON" 
             state "ON", label: 'TV', action: "tv", icon:"st.Electronics.electronics18", backgroundColor: "#53a7c0", nextState:"OFF"             
            }
        standardTile("input3", "device.bd", width: 2, height: 2, decoration: "flat"){
        	state "OFF", label: 'Blu-ray', action: "bd", icon:"st.Electronics.electronics8", backgroundColor: "#FFFFFF",nextState:"ON"  
            state "ON", label: 'Blu-ray', action: "bd", icon:"st.Electronics.electronics8", backgroundColor: "#53a7c0", nextState:"OFF"              
        	}
        standardTile("input4", "device.z2cd", width: 2, height: 2, decoration: "flat"){
        	state "OFF", label: 'Z2 Cast Audio', action: "z2cd", icon:"st.Electronics.electronics14", backgroundColor: "#FFFFFF",nextState:"ON"   
            state "ON", label: 'Z2 Cast Audio', action: "z2cd", icon:"st.Electronics.electronics14", backgroundColor: "#53a7c0", nextState:"OFF"               
        	}
		standardTile("input5", "device.mp", width: 2, height: 2, decoration: "flat"){
        	state "OFF", label: 'Rasplex', action: "mp", icon:"st.Electronics.electronics9", backgroundColor: "#FFFFFF",nextState:"ON"   
            state "ON", label: 'Rasplex', action: "mp", icon:"st.Electronics.electronics9", backgroundColor: "#53a7c0", nextState:"OFF"              
			}
        standardTile("input6", "device.bt", width: 2, height: 2, decoration: "flat"){
        	state "OFF", label: 'Bluetooth', action: "bt", icon:"st.Entertainment.entertainment2", backgroundColor: "#FFFFFF",nextState:"ON"   
            state "ON", label: 'Bluetooth', action: "bt", icon:"st.Entertainment.entertainment2", backgroundColor: "#53a7c0", nextState:"OFF"             
			}           
        standardTile("input8", "device.cd", width: 2, height: 2, decoration: "flat"){
        	state "OFF", label: 'Cast Audio', action: "cd", icon:"st.Entertainment.entertainment2", backgroundColor: "#FFFFFF",nextState:"ON"   
            state "ON", label: 'Cast Audio', action: "cd", icon:"st.Entertainment.entertainment2", backgroundColor: "#53a7c0", nextState:"OFF"             
			}           
		standardTile("input10", "device.sound", width: 4, height: 2, decoration: "flat"){
        	state "sMusic", label: '${currentValue}', action:"sMusic", icon:"st.Entertainment.entertainment3", backgroundColor: "#FFFFFF", nextState:"sMovie"
			state "sMovie", label: '${currentValue}', action:"sMovie", icon:"st.Entertainment.entertainment9", backgroundColor: "#FFFFFF", nextState:"sGame"
			state "sGame", label: '${currentValue}', action:"sGame", icon:"st.Electronics.electronics6", backgroundColor: "#FFFFFF", nextState:"sPure"
			state "sPure", label: '${currentValue}', action:"sPure", icon:"st.Entertainment.entertainment15", backgroundColor: "#FFFFFF", nextState:"sMusic"
            }
        standardTile("input11", "device.q1", width: 1, height: 1, decoration: "flat"){
        	state "OFF", label: 'Quick 1', action: "q1",  backgroundColor: "#53a7c0",nextState:"ON"   // icon:"st.Electronics.electronics5",
            state "ON", label: 'Quick 1', action: "q1", backgroundColor: "#79b821", nextState:"OFF"  //, icon:"st.Electronics.electronics5" 
			}         
        standardTile("input12", "device.q2", width: 1, height: 1, decoration: "flat"){
        	state "OFF", label: 'Quick 2', action: "q2", backgroundColor:"#53a7c0" ,nextState:"ON"   //, icon:"st.Electronics.electronics5"
            state "ON", label: 'Quick 2', action: "q2", backgroundColor: "#79b821" , nextState:"OFF"   
			}         
        standardTile("input13", "device.q3", width: 1, height: 1, decoration: "flat"){
        	state "OFF", label: 'Quick 3', action: "q3", backgroundColor: "#53a7c0",nextState:"ON"   
            state "ON", label: 'Quick 3', action: "q3", backgroundColor: "#79b821", nextState:"OFF"   
			}         
        standardTile("input14", "device.q4", width: 1, height: 1, decoration: "flat"){
        	state "OFF", label: 'Quick 4', action: "q4", backgroundColor: "#53a7c0",nextState:"ON"   
            state "ON", label: 'Quick 4', action: "q4", backgroundColor: "#79b821", nextState:"OFF"   
			}
	standardTile("zone2", "device.zone2", width: 1, height: 1, inactiveLabel: false, decoration: "flat") {
			state "OFF", label:"Zone 2", action:"z2on", backgroundColor:"#53a7c0", nextState:"on"
			state "ON", label:"Zone 2", action:"z2off", backgroundColor:"#79b821", nextState:"off"
        	}            
		standardTile("poll", "device.poll", width: 1, height: 1, decoration: "flat") {
            state "poll", label: "", action: "polling.poll", icon: "st.secondary.refresh", backgroundColor: "#FFFFFF"
        }
main "multiAVR"
        details(["multiAVR", "z2Control", "input7", "input8", "input2", "input3","input4", "input5", "input6","input1", "input10", "input11", "input12","input13", "input14", "zone2", "poll"])
    }
}
def parse(String description) {
	//log.debug "Parsing '${description}'"
 	def map = stringToMap(description)
    if(!map.body || map.body == "DQo=") { return }
	def body = new String(map.body.decodeBase64())
	def statusrsp = new XmlSlurper().parseText(body)
	//POWER STATUS	
    def power = statusrsp.Power.value.text()
	if(power == "ON") { 
    	sendEvent(name: "status", value: 'playing')
    }
    if(power != "" && power != "ON") {  
    	sendEvent(name: "status", value: 'paused')
	}
	//VOLUME STATUS    
    def muteLevel = statusrsp.Mute.value.text()
    if(muteLevel == "on") { 
    	sendEvent(name: "mute", value: 'muted')
	}
    if(muteLevel != "" && muteLevel != "on") {
	    sendEvent(name: "mute", value: 'unmuted')
    }
    if(statusrsp.MasterVolume.value.text()) { 
    	def int volLevel = (int) statusrsp.MasterVolume.value.toFloat() ?: -40.0
        volLevel = (volLevel + 80)
        	log.debug "Adjusted volume is ${volLevel}"
        def int curLevel = 36
        try {
        	curLevel = device.currentValue("level")
        	log.debug "Current volume is ${curLevel}"
        } catch(NumberFormatException nfe) { 
        	curLevel = 36
        }
        if(curLevel != volLevel) {
    		sendEvent(name: "level", value: volLevel)
        }
    } 
	//INPUT STATUS
	def inputCanonical = statusrsp.InputFuncSelect.value.text()
            sendEvent(name: "input", value: inputCanonical)
	        log.debug "Current Input is: ${inputCanonical}"
    
    def inputSurr = statusrsp.selectSurround.value.text()
    		sendEvent(name: "sound", value: inputSurr)
	        log.debug "Current Surround is: ${inputSurr}"  
    def inputZone = statusrsp.RenameZone.value.text()
    		//sendEvent(name: "sound", value: inputSurr)
	        log.debug "Current Active Zone is: ${inputZone}"                      
}
    //TILE ACTIONS
    def setLevel(val) {
        sendEvent(name: "mute", value: "unmuted")     
        sendEvent(name: "level", value: val)
        def int scaledVal = val - 80
        request("cmd0=PutMasterVolumeSet%2F$scaledVal")
    }
    def on() {
        sendEvent(name: "status", value: 'playing')
        request('cmd0=PutZone_OnOff%2FON')
    }
    def off() { 
        sendEvent(name: "status", value: 'paused')
        request('cmd0=PutZone_OnOff%2FOFF')
    }
    def z2on() {
        log.debug "Turning on Zone 2"
        sendEvent(name: "zone2", value: "ON")
        request2('cmd0=PutZone_OnOff%2FON')
        }
    def z2off() {
        log.debug "Turning off Zone 2"
        sendEvent(name: "zone2", value: "OFF")
        request2('cmd0=PutZone_OnOff%2FOFF')
        }
    def mute() { 
        sendEvent(name: "mute", value: "muted")
        request('cmd0=PutVolumeMute%2FON')
    }
    def unmute() { 
        sendEvent(name: "mute", value: "unmuted")
        request('cmd0=PutVolumeMute%2FOFF')
    }
    def toggleMute(){
        if(device.currentValue("mute") == "muted") { unmute() }
        else { mute() }
    }
    def cbl() {
        def cmd = "SAT/CBL"
        log.debug "Setting input to ${cmd}"
        syncTiles(cmd)
        request("cmd0=PutZone_InputFunction%2F" +cmd)
        }
    def tv() {
        def cmd = "TV"
        log.debug "Setting input to ${cmd}"
        syncTiles(cmd)   
        request("cmd0=PutZone_InputFunction%2F"+cmd)
        }
    def bd() {
        def cmd = "BD"
        log.debug "Setting input to ${cmd}"
        syncTiles(cmd)
        request("cmd0=PutZone_InputFunction%2F"+cmd)
        }
    def dvd() {
        def cmd = "DVD"
        log.debug "Setting input to ${cmd}"
        syncTiles(cmd)
        request("cmd0=PutZone_InputFunction%2F"+cmd)
        }
    def cd() {
        def cmd = "CD"
        log.debug "Setting input to ${cmd}"
        syncTiles(cmd)
        request("cmd0=PutZone_InputFunction%2F"+cmd)
        }
    def mp() {
        def cmd = "MPLAY"
        log.debug "Setting input to '${cmd}'"
        syncTiles(cmd)
        request("cmd0=PutZone_InputFunction%2F"+cmd)
        }
    def bt() {
        def cmd = "BT"
        log.debug "Setting input to '${cmd}'"
        syncTiles(cmd)
        request("cmd0=PutZone_InputFunction%2F"+cmd)
    }
    def game() {
        def cmd = "GAME"
        log.debug "Setting input to '${cmd}'" 
        syncTiles(cmd)
        request("cmd0=PutZone_InputFunction%2F"+cmd)
    }
    //SOUND MODES
    def sMusic() {
        def cmd = "MUSIC"
        log.debug "Setting input to '${cmd}'"
        request("cmd0=PutSurroundMode%2F"+cmd)
    }
    def sMovie() { 
        def cmd = "MOVIE"
        log.debug "Setting input to '${cmd}'"
        request("cmd0=PutSurroundMode%2F"+cmd)
    }
    def sGame() {
        def cmd = "GAME"
        log.debug "Setting input to '${cmd}'"
        request("cmd0=PutSurroundMode%2F"+cmd)
    }
    def sPure() {
        def cmd = "PURE DIRECT"
        log.debug "Setting input to '${cmd}'"
        request("cmd0=PutZone_InputFunction%2F"+cmd)
    }
    //QUICK MODES
    def q1() {
        def cmd = "1"
        log.debug "Setting quick input to '${cmd}'"
        syncQTiles(cmd)
        request("cmd0=PutUserMode%2FQuick%2F"+cmd)
    }
    def q2() { 
        def cmd = "2"
        log.debug "Setting quick input to '${cmd}'"
        syncQTiles(cmd)
        request("cmd0=PutSurroundMode%2F"+cmd)
    }
    def q3() {
        def cmd = "3"
        log.debug "Setting quick input to '${cmd}'"
        syncQTiles(cmd)
        request("cmd0=PutSurroundMode%2F"+cmd)
    }
    def q4() {
        def cmd = "4"
        log.debug "Setting quick input to '${cmd}'"
        syncQTiles(cmd)
        request("cmd0=PutZone_InputFunction%2F"+cmd)
    }    
    def poll() { 
        //log.debug "Polling requested"
        refresh()
    }
    def syncTiles(cmd){
        if (cmd == "SAT/CBL") sendEvent(name: "cbl", value: "ON")	 
            else sendEvent(name: "cbl", value: "OFF")						
        if (cmd == "TV") sendEvent(name: "tv", value: "ON")	 
            else sendEvent(name: "tv", value: "OFF")						
        if (cmd == "BD") sendEvent(name: "bd", value: "ON")	 
            else sendEvent(name: "bd", value: "OFF")		
        if (cmd == "CD") sendEvent(name: "cd", value: "ON")	 
            else sendEvent(name: "cd", value: "OFF")
        if (cmd == "DVD") sendEvent(name: "dvd", value: "ON")	 
            else sendEvent(name: "dvd", value: "OFF")						
        if (cmd == "MPLAY") sendEvent(name: "mp", value: "ON")	 
            else sendEvent(name: "mp", value: "OFF")						
        if (cmd == "BT") sendEvent(name: "bt", value: "ON")	 
            else sendEvent(name: "bt", value: "OFF")						
        if (cmd == "GAME") sendEvent(name: "game", value: "ON")	 
            else sendEvent(name: "game", value: "OFF")
    }
    def syncQTiles(cmd){
        if (cmd == "1") sendEvent(name: "q1", value: "ON")	 
            else sendEvent(name: "q1", value: "OFF")						
        if (cmd == "2") sendEvent(name: "q2", value: "ON")	 
            else sendEvent(name: "q2", value: "OFF")						
        if (cmd == "3") sendEvent(name: "q3", value: "ON")	 
            else sendEvent(name: "q3", value: "OFF")						
        if (cmd == "4") sendEvent(name: "q4", value: "ON")	 
            else sendEvent(name: "q4", value: "OFF")						
    }
	def refresh() {
        def hosthex = convertIPtoHex(destIp)
        def porthex = convertPortToHex(destPort)
        device.deviceNetworkId = "$hosthex:$porthex" 

        def hubAction = new physicalgraph.device.HubAction(
                'method': 'GET',
                'path': "/goform/formMainZone_MainZoneXml.xml",
                'headers': [ HOST: "$destIp:$destPort" ] 
            )   
        hubAction
    }
    def request(body) { 
        def hosthex = convertIPtoHex(destIp)
        def porthex = convertPortToHex(destPort)
        device.deviceNetworkId = "$hosthex:$porthex" 

		log.debug "Sending AV cmd - ${destIp}:${destPort}/MainZone/index.put.asp?${body}"

        def hubAction = new physicalgraph.device.HubAction(
                'method': 'POST',
                'path': "/MainZone/index.put.asp",
                'body': body + "&ZoneName=ZONE2",,
                'headers': [ HOST: "$destIp:$destPort" ]
            ) 

        hubAction
    }
    
    private String convertIPtoHex(ipAddress) { 
        String hex = ipAddress.tokenize( '.' ).collect {  String.format( '%02X', it.toInteger() ) }.join()
        return hex
    }
    private String convertPortToHex(port) {
        String hexport = port.toString().format( '%04X', port.toInteger() )
        return hexport
    }
    def getVersionTxt(){
        return "2.1"
    }
1 Like

I am not versed in creating, installing, or using custom device handlers. I tried searching this thread for the issue I am having, but had no luck finding the answer to my questions. So, please be gentle, if this has been asked and answered already. Sorry if this is a bit wordy, but I erred on the side of supplying as much information as I can to make it easier for you to help me.

It would be really cool to have this device handler working properly, especially if I can integrate it with my Alexa app so I can control my AVR-S710W using voice commands.

I can use the Denon app from the Google Play store and the user interface from a web browser to control my receiver, so I know I have good network connectivity to the device. I have the receiver configured to use a static IP, so I won’t have to go in and reconfigure the device once it is finally installed and working properly. Also, in the phone app, from my list of devices, when I tap on the box labeled “PLAYING” the receiver will power off, and the label will change to “PAUSED”. If I tap on the box labeled “PAUSED”, then the receiver will power back on, and the label will change back to read “PLAYING”. So … I know the device handler is able to communicate with my receiver (at least for the power ON/OFF function.)

The Event list shows the status of the device changing from PAUSED to PLAYING when the receiver changes power states.

I used the code from, and published the device handler using the code from https://github.com/sbdobrescu/DenonAVR/blob/master/devicetypes/sb/denon-avr.src/denon-avr.groovy.

I was able to set the IP address and set port 80 of my AVR-S710W by editing the device in the list of My Devices on the web interface. I had to configure it using this method because I can’t open the device using the SmartThings app on my smart phone.

When I try and open the device on my smart phone by tapping on the device name from my My Home > Things screen, the screen will change to a plain white color for a second or two and then returns me to the My Home > Things screen. So, I can’t access any of the custom controls for this device.

I called ST support, and they had the same problem with this DH as I am having. Of course, they could not fully test it because they don’t have a Denon receiver, but they could not get the device to “open” for features other than ON/OFF either.

Are there modifications to the code for the device handler you are aware of that I need to make, or a new device handler someone has written to gain access to the other functions for my receiver?

Mine is doing the same…

Same issue here - I wish some helping mind would look at this and correct!

Same issue

Works great on X1400H! Any chance you will update to get Zone 2 functionality?

Hi can anyone help me - I’ve added the DTH via Github, published it and added a device, added in the IP address and Port 80 (complete guess on the port - no idea how I find this out???). Now every time I open the DTH in the app it causes ST to crash and force-close.

fyi I deleted the device and added it again this time without adding in IP/port info. But still have the same issue, can’t even get to the settings as opening the DTH crashes the ST app…

EDIT - I see a few people are having this issue… Would be great to get a fix!