Merge commit 'klette/master'

This commit is contained in:
Stein Magnus Jodal 2010-03-13 00:25:27 +01:00
commit fd43e17d66
5 changed files with 121 additions and 0 deletions

View File

@ -6,3 +6,4 @@ Contributors to Mopidy in the order of appearance:
* Stein Magnus Jodal <stein.magnus@jodal.no>
* Johannes Knutsen <johannes@knutseninfo.no>
* Thomas Adamcik <adamcik@samfundet.no>
* Kristian Klette <klette@klette.us>

60
mopidy/mixers/denon.py Normal file
View File

@ -0,0 +1,60 @@
import logging
from threading import Lock
from serial import Serial
from mopidy.mixers import BaseMixer
from mopidy.settings import MIXER_PORT
logger = logging.getLogger(u'mopidy.mixers.denon')
"""
Mixer for controlling Denon recivers and amplifiers using the RS-232 protocol.
Connects using the serial specifications from
Denon's RS-232 Protocol specification.
Communication speed : 9600bps
Character length : 8 bits
Parity control : None
Start bit : 1 bit
Stop bit : 1 bit
Communication procedure : Non procedural
Communication data length : 135 bytes (maximum)
The external mixer is the authoritative source for the current volume.
This allows the user to use his remote control the volume without
mopidy cancelling the volume setting.
"""
class DenonMixer(BaseMixer):
def __init__(self):
self._device = Serial(port=MIXER_PORT, timeout=0.2)
self._levels = ['99'] + ["%(#)02d" % {'#': v} for v in range(0, 99)]
self._volume = 0
self._lock = Lock()
def _get_volume(self):
self._lock.acquire();
self.ensure_open_device()
self._device.write('MV?\r')
vol = str(self._device.readline()[2:4])
self._lock.release()
logger.debug(u'_get_volume() = %s' % vol)
return self._levels.index(vol)
def _set_volume(self, volume):
# Clamp according to Denon-spec
if volume > 99:
volume = 99
self._lock.acquire()
self.ensure_open_device()
self._device.write('MV%s\r'% self._levels[volume])
vol = self._device.readline()[2:4]
self._lock.release()
self._volume = self._levels.index(vol)
def ensure_open_device(self):
if not self._device.isOpen():
logger.debug(u'(re)connecting to Denon device')
self._device.open()

View File

@ -38,12 +38,26 @@ CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s [%(threadName)s] %(name)s\n
#: Default on other operating systems::
#:
#: MIXER = u'mopidy.mixers.dummy.DummyMixer'
#:
#: **Available external mixers**
#:
#: .. note::
#: Using external mixers depends on the pyserial library.
#:
#: Denon AVR/AVC via RS-232::
#:
#: MIXER = u'mopidy.mixers.denon.DenonMixer'
#:
MIXER = u'mopidy.mixers.dummy.DummyMixer'
if sys.platform == 'linux2':
MIXER = u'mopidy.mixers.alsa.AlsaMixer'
elif sys.platform == 'darwin':
MIXER = u'mopidy.mixers.osa.OsaMixer'
#: Which port the mixer is connected to if using an external mixer.
#: This must point to the device port like ``/dev/ttyUSB0`` or similar.
MIXER_PORT = None
#: Which address Mopidy should bind to. Examples:
#:
#: ``localhost``

View File

@ -10,6 +10,7 @@ def main():
os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))
r = CoverageTestRunner()
r.add_pair('mopidy/mixers/dummy.py', 'tests/mixers/dummytest.py')
r.add_pair('mopidy/mixers/denon.py', 'tests/mixers/denontest.py')
r.add_pair('mopidy/models.py', 'tests/modelstest.py')
r.add_pair('mopidy/mpd/handler.py', 'tests/mpd/handlertest.py')
r.run()

45
tests/mixers/denontest.py Normal file
View File

@ -0,0 +1,45 @@
import unittest
import os
from mopidy.mixers.denon import DenonMixer
class DenonMixerDeviceMock(object):
def __init__(self):
self._open = True
self.ret_val = bytes('MV00\r')
def write(self, x):
if x[2] != '?':
self.ret_val = bytes(x)
def read(self, x):
return self.ret_val
def isOpen(self):
return self._open
def open(self):
self._open = True
class DenonMixerTest(unittest.TestCase):
def setUp(self):
self.m = DenonMixer()
self.m._device = DenonMixerDeviceMock()
def test_volume_set_to_min(self):
self.m.volume = 0
self.assertEqual(self.m.volume, 0)
def test_volume_set_to_max(self):
self.m.volume = 100
self.assertEqual(self.m.volume, 99)
def test_volume_set_to_below_min_results_in_min(self):
self.m.volume = -10
self.assertEqual(self.m.volume, 0)
def test_volume_set_to_above_max_results_in_max(self):
self.m.volume = 110
self.assertEqual(self.m.volume, 99)
def test_reopen_device(self):
self.m._device._open = False
self.m.volume = 10
self.assertTrue(self.m._device._open)