Denon

From Domoticz
Jump to navigation Jump to search

AV receiver Denon / Marantz

Below a description how to integrate a Denon/Marantz receiver in Domoticz.

All scripts were created and tested on a Denon AVR-X1000, for Marantz or other Denon models it might be required to make some small changes. Goal is to make the setup and scripts compatible with both Makes and models.

This page is based on information found on this page: forum which contains a rough sketch how to implement your Denon into domoticz.


Basic concept

The AV receiver is controlled by dummy devices configured in Domoticz. Although the actions can be triggered in different ways I chose to create one Lua script which is triggered on a Domoticz device change. This way everything is in one place and actions triggered by the dummy device directly caused unjust errors in the Domoticz logs.

The synchronization is done via a bash scripts which runs every 60 seconds via the cron tab. For updating the Power status an additional dummy device is configured as a slave to the Power Switch to prevent loop switching.

The goal is to match the behavior of the receiver and Domoticz as closely as possible, e.g in my case I customized the source inputs names matching my specific application and adopting these into Domoticz. In addition I was able to match the sound levels from the device to the domoticz control.



Currently supported functions:

-- Power On/Off

-- Mute On/Off

-- Volume +/-

-- Select source input



To be implemented:

-- Run as service (higher frequent than 60 seconds)

-- Siri support

-- ....

Prerequisites

bc command must be installed

Setup

Input sources configuration:


Denon receiver

1. Setup custom input source names

  Setup > Inputs > Source Rename >
           CBL/SAT = AMINO
           DVD     = KODI
           Blu-ray = CHROMECAST
           GAME    = PLAYSTATION3

2. Configure volume display

  Setup > Audio > Volume >
           Scale   = 0-98

Domoticz devices

1. Add Dummy devices in Domoticz

  Setup > Hardware > Type = "Dummy" > Add

2. Create DENON_VOLUME

  Setup > Hardware > "Create Virtual Sensor" =>
           Name: "DENON_VOLUME"
           Sensor Type: "Dimmer"
           OK

3. Create DENON_SOURCE

  Setup > Hardware > "Create Virtual Sensor" >
           Name: "DENON_SOURCE"
           Sensor Type: "Selector"
           OK

4. Configure DENON_SOURCE

  Switches > "DENON_SOURCE" > Edit >
           Level 10 Name: "AMINO"
           Level 20 Name: "KODI"
           Level 30 Name: "CHROMECAST"
           Level 40 Name: "PLAYSTATION3"
           Save

Lua Script

1. Goto Domoticz > Setup > Events

2. Select Lua

3. Enter an "Event Name"

4. Copy script below into the editing field

5. Change the values in the section "Definitions" to your specific values

6. Select "Device" in stead of "All" <==== IMPORTANT otherwise you will get unjust errors in the Domoticz log.

7. Make sure "Event active" is checked and save script


-- Control AV receiver (Denon or Marantz)
-- 
-- Author:  Bart77
-- Version: 1.2
-- 
-- Credits:
-- TrixWood to provide a initial version on the forum
--
-- This script will execute actions triggered by virtual devices in Domoticz
-- to control a Denon/Marantz AV receiver.
-- 
-- Currently supported functions:
-- Power On/Off     
-- Source Input select
-- Mute On/Off      
-- Volume +/-
--
-- 1.2 Removed DENON_POWER object, became obsolete by Input Source select
-- 1.1 Added update on Input Source select
-- 1.0 First release
--

-- Definitions
IP = 'xxx.xxx.xxx.xxx'
RECEIVER_VOLUME = "DENON_VOLUME" -- Control MUTE and VOLUME
RECEIVER_SOURCE = "DENON_SOURCE" -- Control OFF and Select Input Source (= ON)

-- Main script
commandArray = {}

if devicechanged[RECEIVER_VOLUME] then -- MUTE and VOLUME
    if (otherdevices[RECEIVER_VOLUME] == "Off") then
        os.execute ("curl http://" .. (IP) .. "/MainZone/index.put.asp?cmd0=PutVolumeMute%2Fon");
        print ("Device:" .. RECEIVER_VOLUME .. " send command Mute = On");
    else
        NewLevel = otherdevices_svalues[RECEIVER_VOLUME] - 80 ; -- Apply offset from absolute to relative
        NewLevel = math.min(NewLevel, 9.5); -- Top Domoticz Scale  
        os.execute ("curl http://" .. (IP) .. "/MainZone/index.put.asp?cmd0=PutVolumeMute%2Foff");
        os.execute ("curl http://" .. (IP) .. "/MainZone/index.put.asp?cmd0=PutMasterVolumeSet/" .. (NewLevel));
        print ("Device:" .. RECEIVER_VOLUME .. " send command Mute = Off; Set Volume = " .. NewLevel);
    end
    
elseif devicechanged[RECEIVER_SOURCE] then -- OFF or INPUT SOURCE SELECT
    -- Translate Selector Switch Level to SourceToSet
    if (otherdevices_svalues[RECEIVER_SOURCE] == '0' ) then
        SourceToSet = "Off";
    elseif (otherdevices_svalues[RECEIVER_SOURCE] == '10' ) then
        SourceToSet = "SAT/CBL";
        SourceCustomName = "AMINO";
    elseif (otherdevices_svalues[RECEIVER_SOURCE] == '20' ) then
        SourceToSet = "DVD";
        SourceCustomName = "KODI";
    elseif (otherdevices_svalues[RECEIVER_SOURCE] == '30' ) then
        SourceToSet = "BD";
        SourceCustomName = "CHROMECAST";
    elseif (otherdevices_svalues[RECEIVER_SOURCE] == '40' ) then
        SourceToSet = "GAME";
        SourceCustomName = "PLAYSTATION3";
    else 
        SourceToSet = "Unknown";
    end
    
    if ( SourceToSet == 'Unknown' ) then
        print ("WARNING: Device:" .. RECEIVER_SOURCE .. " unkown source input" );
    elseif ( SourceToSet == 'Off' ) then -- Switch Off receiver
        os.execute ("curl http://" .. (IP) .. "/MainZone/index.put.asp?cmd0=PutZone_OnOff%2FOFF" );
        print ("Device:" .. RECEIVER_SOURCE .. " send command set source input = OFF");        
    else -- SwitchSource to SourceToSet
        os.execute ("curl http://" .. (IP) .. "/MainZone/index.put.asp?cmd0=PutZone_InputFunction%2F" .. (SourceToSet) );
        print ("Device:" .. RECEIVER_SOURCE .. " send command set source input = " .. (SourceToSet) .. ". => " .. (SourceCustomName) );
    end
end 

return commandArray

Bash Script

1) Create a bash file in /home/pi/domoticz/scripts

2) Copy the script below into the file and save

3) Add this script into to the crontab


#!/bin/bash

# ---------- Declarations ---------------------------------------------------------------------
# Script
VERSION="1.0"							# Script version
LOG="/dev/tty"					    	# Default log to terminal

# Settings Receiver = Device
DEVICE_IP="xxx.xxx.xxx.xxx"           	# Device IP Address
DEVICE_TYPE="Undefined"             	# Device type read from device
DEVICE_STATUS="Undefined"           	# Device status read from device 
DEVICE_VOLUME_SCALE="Undefined"			# Volume scale [Relative/Abolute] <=== Only display value , value read will always be Relative
DEVICE_VOLUME_OFFSET=80					# Volume offset [dB to Abolute] 
DEVICE_XML=(
	'Deviceinfo.xml'
	'formMainZone_MainZoneXmlStatus.xml'
	'formMainZone_MainZoneXml.xml'
	'formNetAudio_StatusXml.xml'
)  										# Source types read from device
   
# Settings Domoticz
DOMO_IP="192.168.77.10"             	# Domoticz IP Address
DOMO_PORT="8080"                    	# Domoticz Port
DOMO_DEVICE_POWER_IDX="115"           	# On/Off    		(Switch) IDX
DOMO_DEVICE_POWER_STATUS_IDX="123"		# Status			(Switch) IDX slave (On/Off)
DOMO_DEVICE_VOL_ABS_IDX="122"        	# Absolute Volume 	(Slider) IDX


# ---------- Usage ---------------------------------------------------------------------
SCRIPT_USAGE()
{

    echo "usage: avreceiver.sh [-h] {-l]

This script will synchronize the status of a AV receiver (Denon / Marantz) with Domoticz.

Supported device types:
	DENON '*AVR-X1000'
	...  Additional models to be added/tested

Version:               $VERSION
Author:                BDV77

[-h]    = Help, display usage.
[-l]    = Log to file 'avreceiver.log' instead of terminal

Version history:
1.0	First release
0.1	Based on Denon script of Trixwood V0.3

to do: 	
	Get source input names from device
	Get custom source input names from device

"
}

# ---------- Read input arguments ---------------------------------------------------------------------
while [ "$1" != "" ]; do
    case $1 in
        -h | --help )           SCRIPT_USAGE
                                exit
                                ;;
        -l )					LOG="avreceiver.log"
                                ;;
        * )                     SCRIPT_USAGE
                                exit 1
    esac
    shift
done

# ---------- Functions ------------------------------------------------------------------------- 

# ---------- Main function --------------------------------------------------------------------- 
echo "$(date +%k:%M:%S.%N) Started avreceiver.sh" > $LOG


# Check if Domiticz status is online and service is running
PINGTIME=$(ping -c 1 -q "$DOMO_IP" | awk -F"/" '{print $5}' | xargs)
if ! expr $PINGTIME '>' 0 &> /dev/null ; then
	echo "Domoticz status = Offline [responsetime = $PINGTIME]" >> $LOG
	exit
fi
if [[ "$(curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command&param=getversion" | grep "Domoticz")" == "" ]] ; then
	echo "Domoticz status = Onine but Domoticz service is not running" >> $LOG
	exit
fi
echo "Domoticz status = Online [responsetime = $PINGTIME] and Domoticz service is running" >> $LOG


# Check if device is online and verify identity
PINGTIME=$(ping -c 1 -q "$DEVICE_IP" | awk -F"/" '{print $5}' | xargs)
if ! expr PINGTIME '>' 0 &> /dev/null ; then
	echo "Device = Offline [responsetime = $PINGTIME]" >> $LOG
	# Set status to offline
	# Define default offline status in Domoticz
fi
echo "Device = Online [responsetime = $PINGTIME]" >> $LOG


# Get device type and try to identity
i=0
for XML in ${DEVICE_XML[@]}; do # Load device data
	XML_DATA[$i]="$(curl -s "http://$DEVICE_IP/goform/$XML")"
	i=$(($i+1))
done
DEVICE_TYPE=$(echo ${XML_DATA[0]} | grep -oPm1 "(?<=<ModelName>)[^<]+")
case $DEVICE_TYPE in
    "") #Nothing found --> not a AV receiver
		echo "No device type <ModelName> could be retreived from $DEVICE_IP/goform/Deviceinfo.xml" >> $LOG
		exit
        ;;
    "*AVR-X1000") #Add other device types that are identical
		echo Succesfully identified a supported device type: $DEVICE_TYPE >> $LOG
        ;;
#    "") #Add other device types here and define differences!
#        ...
#        ;;
    *) #Default to *AVR-X1000??
        echo "An unsupported device type <ModelName> was retreived from $DEVICE_IP/goform/Deviceinfo.xml = $DEVICE_TYPE, Default to *AVR-X1000"  >> $LOG
		DEVICE_TYPE="*AVR-X1000"
esac


# ---------- Update Power (via slave device) --------------------------------------------------------------------- 
POWER_STATUS=$(echo ${XML_DATA[1]} | grep -oPm1 "(?<=<Power><value>)[^<]+") #Read current values from xml data
POWER_STATUS="$(tr '[:lower:]' '[:upper:]' <<< ${POWER_STATUS:0:1})$(tr '[:upper:]' '[:lower:]' <<< ${POWER_STATUS:1})" # Convert to Capitalized, syntax from device is inconsistant

POWER_OLD=$(curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=devices&rid=$DOMO_DEVICE_POWER_IDX" | grep "Status" | cut -d'"' -f4 ) # Get old values from Domoticz

if [ "$POWER_STATUS" != "$POWER_OLD" ] ; then #Only update in case of difference
	curl -s -i -H "Accept: application/json" "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command&param=switchlight&idx=$DOMO_DEVICE_POWER_STATUS_IDX&switchcmd=$POWER_STATUS" &> /dev/null
	echo "Domoticz Object: $DOMO_DEVICE_POWER_STATUS_IDX (POWER), updated to value = $POWER_STATUS" >> $LOG
else
	echo "Domoticz Object: $DOMO_DEVICE_POWER_STATUS_IDX (POWER) in sync, value = $POWER_STATUS" >> $LOG
fi


# ---------- Update Mute and Volume --------------------------------------------------------------------- 
DEVICE_MUTE=$(echo ${XML_DATA[1]} | grep -oPm1 "(?<=<Mute><value>)[^<]+");
DEVICE_MUTE="$(tr '[:lower:]' '[:upper:]' <<< ${DEVICE_MUTE:0:1})$(tr '[:upper:]' '[:lower:]' <<< ${DEVICE_MUTE:1})" # Convert to Capitalized, syntax from device is inconsistant
DEVICE_VOLUME_REL=$(echo ${XML_DATA[1]} | grep -oPm1 "(?<=<MasterVolume><value>)[^<]+") # Volume value always read relative from device
if [[ "$DEVICE_VOLUME_REL" == "--" ]]; then DEVICE_VOLUME_REL=$(echo "-$DEVICE_VOLUME_OFFSET" | bc) ; fi # Convert volume value in case "--"
DEVICE_VOLUME_ABS=$(echo "$DEVICE_VOLUME_OFFSET + "$DEVICE_VOLUME_REL"" | bc) # Calculate absolute volume value
DEVICE_VOLUME_ABS=$(printf "%.*f\n" 0 $DEVICE_VOLUME_ABS) # Round value, due to resolution of Domoticz slider
SLIDER_OLD=$(curl -s "http://$DOMO_IP:$DOMO_PORT/json.htm?type=devices&rid=$DOMO_DEVICE_VOL_ABS_IDX" | grep "Data" | cut -d'"' -f4 ); 
if 	[[ "$SLIDER_OLD" == "Off" ]]; then #Invert Off status of slider to Mute Status On
	MUTE_OLD="On"
else #Invert On status of slider to Mute Status Off
	MUTE_OLD="Off"
	if [[ "$SLIDER_OLD" != "On" ]]; then #if actual value is displayed, read value
		VOLUME_ABS_OLD=$(echo "$SLIDER_OLD" | grep -Eo '[0-9]{1,4}');
	fi
fi

if [[ "$DEVICE_MUTE" != "$MUTE_OLD" ]]; then #Only update in case of difference
	curl -s -i -H "Accept: application/json" "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command&param=switchlight&idx=$DOMO_DEVICE_VOL_ABS_IDX&switchcmd=$MUTE_OLD" &> /dev/null
	echo "Domoticz Object: $DOMO_DEVICE_VOL_ABS_IDX (Mute), updated to value = $MUTE_OLD" >> $LOG
else
	echo "Domoticz Object: $DOMO_DEVICE_VOL_ABS_IDX (Mute) in sync, value = $MUTE_OLD" >> $LOG
fi
if [[ "$DEVICE_VOLUME_ABS" != "$VOLUME_ABS_OLD" ]] && [[ "$DEVICE_MUTE" == "Off" ]]; then #Only update in case of difference and Mute = Off
	curl -s -i -H "Accept: application/json" "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command&param=switchlight&idx=$DOMO_DEVICE_VOL_ABS_IDX&switchcmd=Set%20Level&level=$(($DEVICE_VOLUME_ABS + 1))" &> /dev/null
	if [ "$DEVICE_VOLUME_ABS" = 0 ] ; then # If set to zero correct for auto switch to mute <=== THIS WILL SWICH EACH TIME BECAUSE VALUE ZERO WILL NOT BE DISPLAYED :(
		curl -s -i -H "Accept: application/json" "http://$DOMO_IP:$DOMO_PORT/json.htm?type=command&param=switchlight&idx=$DOMO_DEVICE_VOL_ABS_IDX&switchcmd=On" &> /dev/null
	fi
	echo "Domoticz Object: $DOMO_DEVICE_VOL_ABS_IDX (Volume), updated to value = $DEVICE_VOLUME_ABS" >> $LOG
else
	echo "Domoticz Object: $DOMO_DEVICE_VOL_ABS_IDX (Volume) in sync, value = $DEVICE_VOLUME_ABS" >> $LOG
fi

	
echo "$(date +%k:%M:%S.%N) Stoppped avreceiver.sh" >> $LOG

exit 0