Denon Home Theater

Use LogicMachine as a TCP client for reading data from Home Theater #

Task #

  • Establish TCP communication with external TCP server – Denon Home Theater
  • Read from Denon and show on visualization:
    – boolean object with Denon ON/OFF status
    – string object with radio station currently playing

Resident script #

Add the following code into the resident script, set sleep time to 0.

-- first call
if not ready then
  require('socket')

  warningclosed = true
  warningfailed = true
  warningerrors = true
  warningtimeou = true
  denonstatus = false
  lastdatareceived = nil

  -- incoming command parser
  function parse(data)
    if data == 'PWON' then
      denonstatus = true
    elseif data == 'PWSTANDBY' then
      denonstatus = false
    elseif string.sub(data, 1, 4) == 'NSE0' then
      grp.write('5/2/2', string.sub(data, 5))
    elseif string.sub(data, 1, 4) == 'NSE1' then
      grp.write('5/2/3', string.sub(data, 5))
    else
      -- log other info, not mapped, if useful
      log(data)
    end

    -- check if Denon changed status and sent new Object value in the bus only for changes
    currentdenonstatus = grp.getvalue('5/2/1')
    if currentdenonstatus ~= denonstatus then
      grp.write('5/2/1', denonstatus)
    end
  end

  ready = true
end

-- client connected
if connected then
  -- send status request, in order to keep the socket live
  -- Denon sends PWON each second automatically on the socket, no request necessary
  --client:send('PW?\r')

  while true do
    char, err = client:receive(1)

    if char ~= nil then
      lastdatareceived = os.time()
      warningclosed = true
      warningfailed = true
      warningerrors = true
      warningtimeou = true
    else
      now = os.time()
      deltatime = now - lastdatareceived
    end

    -- error while receiving, timeout or closed socket
    if err then
      -- remote server closed connection, reconnect
      if err == 'closed' then
        connected = false
        if warningclosed then alert('[tcp-client] connection closed') end
        warningclosed = false
        sleep(1)
      elseif err == 'timeout' then
        connected = false
        if warningtimeou then alert('[tcp-client] connection timeout') end
        warningtimeou = false
        sleep(1)
      elseif warningerrors then alert('[tcp-client] connection failed: %s', err)
        warningerrors = false
      end

      break

    -- end of line, parse buffer
    elseif char == '\r' then
      data = table.concat(buffer)
      parse(data)
      buffer = {}

      -- wait some time before next request
      --sleep(1)

      break
    -- other char, add to buffer
    else
      table.insert(buffer, char)
    end
  end
-- first call or previously disconnected
else
  -- close previous connection when disconnected
  if client then
    client:close()
    client = nil
  end

  -- create tcp client
  client = socket.tcp()
  client:settimeout(5)
  connected, err = client:connect('172.16.1.111', 23)

  -- connect ok, reset buffer
  if connected then
    lastdatareceived = os.time()
    warningclosed = true
    warningfailed = true
    warningerrors = true
    warningtimeou = true
    alert('[tcp-client] connection ok')
    buffer = {}
    sleep(5)
  -- error while connecting,
  else
    if warningfailed then alert('[tcp-client] connection failed (conn): %s', err) end
    warningfailed = false
    sleep(5)
  end
end

LogicMachine output #

  • TCP connection state – OK, closed, timeout, failed

Theater tcp-client_logic_machine

  • Log other info, not mapped, if useful

Theater tcp-client_logic_machine_logs

  • Object values

Theater tcp-client_logic_machine_radio-stations

Other Denon control protocol #

You can download Denon device protocol here to see what information you can receive from your player.

Theater pdf_icon Denon protocol

Created by Giovanni Aduso from Schüco