Correct since the latest version you have to do some modifications:
What I did, I created under custom_components a folder called “Marantz” under this folder are 2 files,
__init__.py
(this file is empty)
media_player.py
"""
Support for interfacing with Marantz receivers through RS-232.
For more details about this platform, please refer to the documentation at
"""
import logging
import voluptuous as vol
from homeassistant.components.media_player import (
MediaPlayerDevice,
PLATFORM_SCHEMA)
from homeassistant.components.media_player.const import (
# from homeassistant.components.media_player import (
SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_MUTE, SUPPORT_TURN_ON, SUPPORT_TURN_OFF,
SUPPORT_VOLUME_STEP, SUPPORT_SELECT_SOURCE, SUPPORT_SELECT_SOUND_MODE
#, MediaPlayerDevice,
# PLATFORM_SCHEMA)
)
from homeassistant.const import (
CONF_NAME, STATE_OFF, STATE_ON)
import homeassistant.helpers.config_validation as cv
#REQUIREMENTS = ['marantz_receiver==0.0.1']
#REQUIREMENTS = ['https://github.com/andrewpc/marantz_receiver/archive/0.0.0.1.zip']
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Marantz Receiver'
DEFAULT_MIN_VOLUME = -71
DEFAULT_MAX_VOLUME = -1
SUPPORT_MARANTZ = SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_VOLUME_STEP | \
SUPPORT_SELECT_SOURCE | SUPPORT_SELECT_SOUND_MODE
CONF_SERIAL_PORT = 'serial_port'
CONF_MIN_VOLUME = 'min_volume'
CONF_MAX_VOLUME = 'max_volume'
CONF_SOURCE_DICT = 'sources'
CONF_SOUNDMODE_DICT = 'soundmode'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SERIAL_PORT): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_MIN_VOLUME, default=DEFAULT_MIN_VOLUME): int,
vol.Optional(CONF_MAX_VOLUME, default=DEFAULT_MAX_VOLUME): int,
vol.Optional(CONF_SOURCE_DICT, default={}): {cv.string: cv.string},
vol.Optional(CONF_SOUNDMODE_DICT, default={}): {cv.string: cv.string},
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Marantz platform."""
from marantz_receiver import MarantzReceiver
add_devices([Marantz(
config.get(CONF_NAME),
MarantzReceiver(config.get(CONF_SERIAL_PORT)),
config.get(CONF_MIN_VOLUME),
config.get(CONF_MAX_VOLUME),
config.get(CONF_SOURCE_DICT),
config.get(CONF_SOUNDMODE_DICT)
)], True)
class Marantz(MediaPlayerDevice):
"""Representation of a Marantz Receiver."""
def __init__(self, name, marantz_receiver, min_volume, max_volume,
source_dict, sound_mode_dict):
"""Initialize the Marantz Receiver device."""
self._name = name
self._marantz_receiver = marantz_receiver
self._min_volume = min_volume
self._max_volume = max_volume
self._source_dict = source_dict
self._sound_mode_dict = sound_mode_dict
self._reverse_mapping = {value: key for key, value in
self._source_dict.items()}
self._reverse_mapping_sound_mode = {value: "0{}".format(key) for key, value in
self._sound_mode_dict.items()}
self._volume = self._state = self._mute = self._source = None
def calc_volume(self, decibel):
"""
Calculate the volume given the decibel.
Return the volume (0..1).
"""
return abs(self._min_volume - decibel) / abs(
self._min_volume - self._max_volume)
def calc_db(self, volume):
"""
Calculate the decibel given the volume.
Return the dB.
"""
return self._min_volume + round(
abs(self._min_volume - self._max_volume) * volume)
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the state of the device."""
return self._state
def update(self):
"""Retrieve latest state."""
if self._marantz_receiver.main_power(':', '?') == '1':
self._state = STATE_OFF
else:
self._state = STATE_ON
if self._marantz_receiver.main_mute(':', '?') == '1':
self._mute = False
else:
self._mute = True
volume_result = self._marantz_receiver.main_volume(':', '?')
if (volume_result != None):
self._volume = self.calc_volume(volume_result)
self._source = self._source_dict.get(
self._marantz_receiver.main_source(':', '?'))
self._sound_mode = self._sound_mode_dict.get(
self._marantz_receiver.main_sound_mode(':', '?'))
@property
def volume_level(self):
"""Volume level of the media player (0..1)."""
return self._volume
@property
def is_volume_muted(self):
"""Boolean if volume is currently muted."""
return self._mute
@property
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_MARANTZ
def turn_off(self):
"""Turn the media player off."""
self._marantz_receiver.main_power(':', '3')
def turn_on(self):
"""Turn the media player on."""
self._marantz_receiver.main_power(':', '2')
def volume_up(self):
"""Volume up the media player."""
self._marantz_receiver.main_volume(':', '1')
def volume_down(self):
"""Volume down the media player."""
self._marantz_receiver.main_volume(':', '2')
def set_volume_level(self, volume):
"""Set volume level, range 0..1."""
vol_calc = '0' + str(self.calc_db(volume))
self._marantz_receiver.main_volume(':', vol_calc)
def select_source(self, source):
"""Select input source."""
self._marantz_receiver.main_source(':', self._reverse_mapping.get(source))
def select_sound_mode(self, sound_mode):
"""Select sound mode."""
self._marantz_receiver.main_sound_mode(':', self._reverse_mapping_sound_mode.get(sound_mode))
def mute_volume(self, mute):
"""Mute (true) or unmute (false) media player."""
if mute:
self._marantz_receiver.main_mute(':', '2')
else:
self._marantz_receiver.main_mute(':', '1')
@property
def source(self):
"""Name of the current input source."""
return self._source
@property
def sound_mode(self):
"""Name of the current sound_mode."""
return self._sound_mode
@property
def source_list(self):
"""List of available input sources."""
return sorted(list(self._reverse_mapping.keys()))
@property
def sound_mode_list(self):
"""List of available sound_modes."""
return sorted(list(self._reverse_mapping_sound_mode.keys()))
Under a different folder called deps -> lib -> site-packages -> marantz_receiver are 2 files:
__init__.py
"""
Marantz has an RS232 interface to control the receiver.
Not all receivers have all functions.
Functions can be found on in the xls file within this repository
"""
import codecs
import socket
from time import sleep
from marantz_receiver.marantz_commands import CMDS
import serial # pylint: disable=import-error
import threading
import telnetlib
import logging
import time
DEFAULT_TIMEOUT = 0.5
DEFAULT_WRITE_TIMEOUT = 0.5
_LOGGER = logging.getLogger(__name__)
class MarantzReceiver(object):
"""Marantz receiver."""
def __init__(self, serial_port, timeout=DEFAULT_TIMEOUT,
write_timeout=DEFAULT_WRITE_TIMEOUT):
"""Create RS232 connection."""
self.ser = serial.Serial(serial_port, baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=timeout,
write_timeout=write_timeout)
self.lock = threading.Lock()
def exec_command(self, domain, function, operator, value=None):
"""
Write a command to the receiver and read the value it returns.
The receiver will always return a value, also when setting a value.
"""
raw_command = CMDS[domain][function]['cmd']
if operator in CMDS[domain][function]['supported_operators']:
if value is None:
raise ValueError('No value provided')
else:
cmd = ''.join([raw_command, operator, str(value)])
else:
raise ValueError('Invalid operator provided %s' % operator)
with self.lock:
if not self.ser.is_open:
self.ser.open()
self.ser.reset_input_buffer()
self.ser.reset_output_buffer()
# self.lock.acquire()
# Marantz uses the prefix @ and the suffix \r, so add those to the above cmd.
final_command = ''.join(['@', cmd, '\r']).encode('utf-8')
_LOGGER.debug ('Send Command %s',final_command)
self.ser.write(final_command)
msg = self.ser.read_until(bytes('\r'.encode()))
# self.lock.release()
_LOGGER.debug ('Response msg %s', msg.decode())
split_string = msg.decode().strip().split(':')
_LOGGER.debug("Decoded split string %s", split_string)
_LOGGER.debug ("Original command: %s", raw_command)
# Check return value contains the same command value as requested. Sometimes the marantz gets out of sync. Ignore if this is the case
if split_string[0] != ('@' + raw_command):
_LOGGER.debug ("Send & Response command values dont match %s != %s - Ignoring returned value", split_string[0], '@' + raw_command )
return None
else:
return split_string[1]
# b'AMT:0\r will return 0
def main_mute(self, operator, value=None):
"""Execute Main.Mute."""
return self.exec_command('main', 'mute', operator, value)
def main_power(self, operator, value=None):
"""Execute Main.Power."""
return self.exec_command('main', 'power', operator, value)
def main_volume(self, operator, value=None):
"""
Execute Main.Volume.
Returns int
"""
vol_result = self.exec_command('main', 'volume', operator, value)
if vol_result != None:
return int(vol_result)
def main_source(self, operator, value=None):
"""Execute Main.Source."""
result = self.exec_command('main', 'source', operator, value)
"""
The receiver often returns the source value twice. If so take the
second value as the source, otherwise return original
"""
if result != None and len(result) == 2:
_LOGGER.debug("Source Result: %s", result[1])
return result[1]
else:
return result
def main_sound_mode(self, operator, value=None):
"""Execute Main.SoundMode."""
result_sound_mode = self.exec_command('main', 'sound_mode', operator, value)
# if result_sound_mode != None and len(result_sound_mode) == 2:
# _LOGGER.debug("Sound_Mode Result: %s", result_sound_mode[1])
# return result_sound_mode[1]
# else:
# return result_sound_mode
if result_sound_mode != None :
return result_sound_mode
def main_autostatus (self, operator, value=None):
"""
Execute autostatus.
Not currently used but will allow two-way communications in future
Returns int
"""
return int(self.exec_command('main', 'autostatus', operator, value))
marantz_commands.py
"""
Commands and operators used by Marantz.
CMDS[domain][function]
Majority of Marantz commands use ':' as operator although there are also some
multi-zone commands that use '='
"""
CMDS = {
'main':
{
'mute':
{'cmd': 'AMT',
'supported_operators': [':']
},
'power':
{'cmd': 'PWR',
'supported_operators': [':']
},
'volume':
{'cmd': 'VOL',
'supported_operators': [':']
},
'source':
{'cmd': 'SRC',
'supported_operators': [':']
},
'sound_mode':
{'cmd': 'SUR',
'supported_operators': [':']
},
'autostatus':
{'cmd': 'AST',
'supported_operators': [':']
}
}
}