Author Topic: Control Denon AVR (plugin-free solution)  (Read 7307 times)

Offline cedricm

  • Sr. Newbie
  • *
  • Posts: 37
  • Karma: +1/-0
Control Denon AVR (plugin-free solution)
« on: February 03, 2014, 05:41:41 am »
Hi,

As an alternative to the Denon Plugin, here is a LUUP-scene based implementation that allows control of a Denon A/V receiver.

The idea of not using the plugin is to avoid a persistent connection to the AVR (and errors when it's not powered on) & remove a dependency.
This LUUP code provides a short & simple solution, which allows scenes as "Turn AVR ON if currently OFF, set volume to xx and switch to favorite station x".

Common code that can either be put in Startup LUA, or at the beginning of the scene:


local socket = require "socket"
local denon_tcp

function logDenon(msg)
    luup.log("DENON: " .. msg)
end

function connectDenon()
    if denon_tcp then
        logDenon("Already connected")
        return false
    else
        logDenon("Connecting...")
        denon_tcp = assert(socket.tcp())
        denon_tcp:settimeout(0.5)
        local status, error = denon_tcp:connect("<ip address of denon AVR>", 23)
        if status then
            logDenon("Connected")
            return true
        else
            denon_tcp = nil
            logDenon("Error connecting: " .. error)
            return false
        end
    end
end

function sendDenon(cmd)
    local buf = "", s, status, partial
    status = nil
    logDenon("Sending " .. cmd)
    denon_tcp:send(cmd .. "\r")
    while not status do
        s, status, partial = denon_tcp:receive(1)
        if s == "\r" then
            status = true
        else
            if not status then
                buf = buf .. s
            else
                logDenon("Error receiving: " .. status)
            end
        end
    end
    logDenon("Received " .. buf)
    sleepDenon()
    return buf
end

function disconnectDenon()
    logDenon("Disconnecting...")
    denon_tcp:close()
    denon_tcp = nil
    logDenon("Disconnected")
end

function sleepDenon()
    luup.sleep(500)
end

function powerOnDenon()
    local pw_status = sendDenon("PW?")
    if pw_status == "PWSTANDBY" then
        sendDenon("PWON")
        sleepDenon()
    end
end

function powerOffDenon()
    sendDenon("PWSTANDBY")
end


Example of use:

if connectDenon() then
    powerOnDenon()
    sendDenon("MV15") -- set volume to 15
    sendDenon("ZMFAVORITE3") -- switch to favorite station 3
    disconnectDenon()
end

« Last Edit: February 05, 2014, 09:48:42 am by cedricm »

Offline mda

  • Sr. Member
  • ****
  • Posts: 464
  • Karma: +9/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #1 on: February 03, 2014, 02:13:46 pm »
thanks! i will test with an AVR 4520 and let you know how it goes.

Offline mda

  • Sr. Member
  • ****
  • Posts: 464
  • Karma: +9/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #2 on: February 04, 2014, 02:06:33 am »
@cedricm

do i need to worry about "LEAK" in my log? Thanks!

Code: [Select]
50 02/03/14 22:58:24.337 luup_log:0: DENON: Sending Z2? __LEAK__ this:77824 start:2199552 to 0x26cc000 <0x33cec680>
50 02/03/14 22:58:24.364 luup_log:0: DENON: Received Z2OFF __LEAK__ this:4096 start:2203648 to 0x26cd000 <0x33cec680>
50 02/03/14 22:58:24.880 luup_log:0: DENON: Disconnecting... <0x33cec680>
50 02/03/14 22:58:24.910 luup_log:0: DENON: Disconnected <0x33cec680>
50 02/03/14 22:58:48.287 luup_log:0: DENON: Connecting... <0x33cec680>
50 02/03/14 22:58:48.420 luup_log:0: DENON: Connected <0x33cec680>
50 02/03/14 22:58:48.432 luup_log:0: DENON: Sending Z2? <0x33cec680>
50 02/03/14 22:58:48.446 luup_log:0: DENON: Received  <0x33cec680>
50 02/03/14 22:58:48.960 luup_log:0: DENON: Disconnecting... <0x33cec680>
50 02/03/14 22:58:48.972 luup_log:0: DENON: Disconnected <0x33cec680>
50 02/03/14 22:59:22.237 luup_log:0: DENON: Connecting... <0x33cec680>
50 02/03/14 22:59:22.318 luup_log:0: DENON: Connected __LEAK__ this:28672 start:2277376 to 0x26df000 <0x33cec680>
50 02/03/14 22:59:22.330 luup_log:0: DENON: Sending MVUP <0x33cec680>
50 02/03/14 22:59:22.344 luup_log:0: DENON: Received  <0x33cec680>
50 02/03/14 22:59:22.859 luup_log:0: DENON: Disconnecting... <0x33cec680>
50 02/03/14 22:59:22.871 luup_log:0: DENON: Disconnected <0x33cec680>
50 02/03/14 23:02:48.215 luup_log:0: DENON: Connecting... <0x33cec680>
50 02/03/14 23:02:48.248 luup_log:0: DENON: Connected __LEAK__ this:53248 start:2662400 to 0x273d000 <0x33cec680>
50 02/03/14 23:02:48.269 luup_log:0: DENON: Sending MVUP __LEAK__ this:16384 start:2678784 to 0x2741000 <0x33cec680>
50 02/03/14 23:02:48.296 luup_log:0: DENON: Received  <0x33cec680>
50 02/03/14 23:02:48.949 luup_log:0: DENON: Disconnecting... <0x33cec680>
50 02/03/14 23:02:48.961 luup_log:0: DENON: Disconnected __LEAK__ this:8192 start:2764800 to 0x2756000 <0x33cec680>
root@MiOS_30003318:~#
« Last Edit: February 04, 2014, 02:17:40 am by mda »

Offline mda

  • Sr. Member
  • ****
  • Posts: 464
  • Karma: +9/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #3 on: February 04, 2014, 02:17:22 am »
@cedricm

I seem to be having trouble receiving feedback.

Code: [Select]
50 02/03/14 23:07:02.826 luup_log:0: DENON: Connecting... <0x33cec680>
50 02/03/14 23:07:02.901 luup_log:0: DENON: Connected <0x33cec680>
50 02/03/14 23:07:02.913 luup_log:0: DENON: Sending MV? <0x33cec680>

50 02/03/14 23:07:02.927 luup_log:0: DENON: Received  <0x33cec680>

50 02/03/14 23:07:03.441 luup_log:0: DENON: Disconnecting... <0x33cec680>
50 02/03/14 23:07:03.460 luup_log:0: DENON: Disconnected <0x33cec680>
50 02/03/14 23:07:25.561 luup_log:0: DENON: Connecting... <0x33cec680>
50 02/03/14 23:07:25.637 luup_log:0: DENON: Connected <0x33cec680>
50 02/03/14 23:07:25.649 luup_log:0: DENON: Sending PW? <0x33cec680>

50 02/03/14 23:07:25.663 luup_log:0: DENON: Received  <0x33cec680>

50 02/03/14 23:07:26.177 luup_log:0: DENON: Disconnecting... <0x33cec680>
50 02/03/14 23:07:26.191 luup_log:0: DENON: Disconnected <0x33cec680>

the denon 4520 is on and does, for example change the volume when i  tell it to so i know it is connecting.

Code: [Select]
50 02/03/14 23:10:12.391 luup_log:0: DENON: Connecting... <0x33cec680>
50 02/03/14 23:10:12.580 luup_log:0: DENON: Connected <0x33cec680>
50 02/03/14 23:10:13.381 luup_log:0: DENON: Sending MV32 <0x33cec680>
50 02/03/14 23:10:13.397 luup_log:0: DENON: Received  <0x33cec680>
50 02/03/14 23:10:13.911 luup_log:0: DENON: Disconnecting... <0x33cec680>
50 02/03/14 23:10:13.924 luup_log:0: DENON: Disconnected <0x33cec680>

if i restart Lua, i can receive feedback once, but not again until i restart Lua

Code: [Select]
50 02/03/14 23:13:32.432 luup_log:0: DENON: Connecting... <0x32c32680>
50 02/03/14 23:13:32.593 luup_log:0: DENON: Connected <0x32c32680>
50 02/03/14 23:13:32.609 luup_log:0: DENON: Sending MV? <0x32c32680>

50 02/03/14 23:13:32.634 luup_log:0: DENON: Received MV32 <0x32c32680>

50 02/03/14 23:13:33.151 luup_log:0: DENON: Disconnecting... <0x32c32680>
50 02/03/14 23:13:33.163 luup_log:0: DENON: Disconnected <0x32c32680>
50 02/03/14 23:15:14.201 luup_log:0: DENON: Connecting... <0x32c32680>
50 02/03/14 23:15:14.276 luup_log:0: DENON: Connected <0x32c32680>
50 02/03/14 23:15:14.288 luup_log:0: DENON: Sending MV? <0x32c32680>

50 02/03/14 23:15:14.300 luup_log:0: DENON: Received  <0x32c32680>

50 02/03/14 23:15:14.819 luup_log:0: DENON: Disconnecting... <0x32c32680>
50 02/03/14 23:15:14.832 luup_log:0: DENON: Disconnected <0x32c32680>

Please let me know if there is anything i can do to help figure this out !

Thanks

Offline cedricm

  • Sr. Newbie
  • *
  • Posts: 37
  • Karma: +1/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #4 on: February 04, 2014, 03:20:28 am »
Hi!

Hmm, thinking about it: it seems to me that the Denon AVR doesn't really like having multiple simultaneous TCP connections.
On my 2313, if I telnet to the denon:23, I can send commands & receive results. However, if I keep it open, this blocks other clients.

That was one reason for me to write this scene: it just connects while performing requested actions and disconnect right away... so that I can also use my laptop media keys to control volume playback on the Denon too.

Make sure that nothing else tries to connect to the Denon (and keeps a connection open), e.g., the plugin or whatever.


Offline mda

  • Sr. Member
  • ****
  • Posts: 464
  • Karma: +9/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #5 on: February 04, 2014, 03:34:31 am »
i do not think there is anything else connecting to it. curiously it receives info back after a luup restart, but then it does not. if i then restart luup it immediately receives just once then stops receiving again. however, it will respond to commands (e.g. to change the volume) even when it is not receiving responses. So it does not feel like it is something else getting in the way as best i can tell.

if we can't figure it out on port 23 (which would be ideal if we can of course), i wonder if we should try connecting on Port 80 per this post?... http://www.roomieremote.com/faq/#denon

thanks
« Last Edit: February 04, 2014, 03:47:57 am by mda »

Offline cedricm

  • Sr. Newbie
  • *
  • Posts: 37
  • Karma: +1/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #6 on: February 04, 2014, 03:50:40 am »
Are you sure that the plugin is not trying to connect too?

The code should properly release the connection (at least, that's the case here).

Can you run from the console :
$ netstat -an | grep <ip address>

1. just before the first execution of the scene
=> no connection should be shown. If you see one, restart LUUP or reboot and try again.

2. during/right after the execution of the scene
=> a connection to <ip address>:23 should be visible

3. a couple of minutes after
=> no connection should be shown


Using the undocumented protocol on :80 might be easier/more robust... if you find some documentation somewhere! (in that case, calling luup.inet.wget with the right parameters might be just what is needed).
« Last Edit: February 04, 2014, 03:53:52 am by cedricm »

Offline cedricm

  • Sr. Newbie
  • *
  • Posts: 37
  • Karma: +1/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #7 on: February 04, 2014, 03:58:00 am »
Sorry, I missed the part where you are saying that it's responding to commands even if reply can't be read.
This code stops reading the reply as soon as it receives a carriage return (\r) character. Maybe your unit sends more than one or whatever.
Might need to change the code to read as much data as it can until it blocks.

Offline mda

  • Sr. Member
  • ****
  • Posts: 464
  • Karma: +9/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #8 on: February 04, 2014, 04:01:49 am »
Is there anything I can do to help test whether the problem is extra r 's?


Sent from my iPhone using Tapatalk

Offline mda

  • Sr. Member
  • ****
  • Posts: 464
  • Karma: +9/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #9 on: February 04, 2014, 04:08:19 am »
I confirmed no connection to the denon before I run the scene or after I run it (and a connection when running it). The same when it responds and when it does not-- so I think you are probably right about the content received being the issue, perhaps with extra r's


Sent from my iPhone using Tapatalk

Offline cedricm

  • Sr. Newbie
  • *
  • Posts: 37
  • Karma: +1/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #10 on: February 04, 2014, 04:10:57 am »
Start coding ;)

I don't have much time to invest in this (and since it's working for me... ;) ).
You may want to try changing the sendDenon code to something like (totally untested):

function sendDenon(cmd)
    local buf = "", s, status, partial
    logDenon("Sending " .. cmd)
    denon_tcp:send(cmd .. "\r")
    while not status do
        s, status, partial = denon_tcp:receive(1)
        if not status then
            buf = buf .. s
        else
            logDenon("Error receiving: " .. status)
        end
    end
    logDenon("Received " .. buf)
    sleepDenon()
    return buf
end


You should get a timeout error after half a second, but this should also read as much data as it can (including trailing \r that would need to be removed later).
Might be interesting to see if it gets any the second time you run the scene.

Offline mda

  • Sr. Member
  • ****
  • Posts: 464
  • Karma: +9/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #11 on: February 04, 2014, 05:00:57 am »
Code: [Select]
Start coding ;)

trying :)

i tried the new code and it does not work either. i put some logging code into the original and discovered that on the second try, it never gets past

Code: [Select]
while not status do

i wish i knew enough Lua to have a clue what might be going on ;)

Offline cedricm

  • Sr. Newbie
  • *
  • Posts: 37
  • Karma: +1/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #12 on: February 04, 2014, 05:06:02 am »
hmm, replace

local buf = "", s, status, partial


with

local buf = "", s, status = nil, partial



Quick comment on the code: it's currently reading the reply coming from the AVR one char at a time in the "while... do ... end" loop. So it needs to know when to stop:

while not status do

simply loops as long as the "status" variable is null. If an error happens (connection lost, timeout...), status will be a string containing the error name... which will stop the loop.


Offline mda

  • Sr. Member
  • ****
  • Posts: 464
  • Karma: +9/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #13 on: February 04, 2014, 05:08:53 am »
Yes that's it! Thanks so much.

EDIT: actually that gave me a lua error on startup, but adding " status = false " below that original line worked.
« Last Edit: February 04, 2014, 05:11:30 am by mda »

Offline cedricm

  • Sr. Newbie
  • *
  • Posts: 37
  • Karma: +1/-0
Re: Control Denon AVR (plugin-free solution)
« Reply #14 on: February 04, 2014, 05:10:50 am »
Oh, that's great!
I didn't know that LUA could play such tricks with uninitialized variables :D Thanks for helping debugging!

I'm updating my first post then.