joopert / nad_receiver

python api to connect to NAD receivers
MIT License
11 stars 18 forks source link

Exception thrown when updating Mute state #60

Open kengruven opened 4 days ago

kengruven commented 4 days ago

When I call main_mute('=', ...) to set the mute state, my receiver correctly mutes (or unmutes), but it throws an exception with the response:

>>> r.main_mute('?')
'Off'
>>> r.main_mute('=', 'On')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ken/Downloads/nad_receiver/nad_receiver/__init__.py", line 64, in main_mute
    return self.exec_command('main', 'mute', operator, value)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ken/Downloads/nad_receiver/nad_receiver/__init__.py", line 51, in exec_command
    msg = self.transport.communicate(cmd)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ken/Downloads/nad_receiver/nad_receiver/nad_transport.py", line 54, in communicate
    return msg.strip().decode()
           ^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xde in position 1: invalid continuation byte
joopert commented 3 days ago

Hi @kengruven, apparently the UTF-8 encoding is not what your receiver is sending. Can you tell which receiver you have? Perhaps in the documentation it is written what encoding is used.

kengruven commented 3 days ago

I have an NAD T747, and the control documentation is basically nonexistent.

I tried running the internals step-by-step manually (albeit without locking):

>>> r = NADReceiver("/dev/ttyUSB0")
>>> r.transport.ser.reset_input_buffer()
>>> r.transport.ser.write(f"\rMain.Mute=Off\r".encode("utf-8"))
15
>>> r.transport.ser.read_until(serial.CR)
b'\r'
>>> r.transport.ser.read_until(serial.CR)
b'Tuner.FM.RDSName=erson Su\r'
>>> r.transport.ser.read_until(serial.CR)
b'Tuner.FM.RDSName=Ben Patt\r'

# ...lots more of these, until finally...

>>> r.transport.ser.read_until(serial.CR)
b'\xddXZl\xdan.Mute=Off\r'

It seems to be dumping either all RDS updates or all display updates (the display shows RDS status) into the response stream.

In all cases, though, before it finally receives "Mute=Off", it gets some non-ASCII bytes. I tried adding a line at nad_transport.py right before the end of communicate(...) to catch this (and switched to a non-FM source, so RDS wouldn't interfere):

assert isinstance(msg, bytes)
print("DEBUG: msg=`%s`" % msg)  # <-- added
return msg.strip().decode()

and some of the values I see are:

DEBUG: msg=`b'm\xacZ\xec\xdan.Mute=On\r'`
DEBUG: msg=`b'm\xacZl\xdan.Mute=Off\r'`
DEBUG: msg=`b'5\xd6-\xb6m\xb7.Mute=On\r'`
DEBUG: msg=`b'\xadXZl\xda\x7f.Mute=Off\r'`
DEBUG: msg=`b'5\xde-\xb6m\xb7.Mute=On\r'`
DEBUG: msg=`b'\xcdXZ\xac\xdan.Mute=Off\r'`

It seems to always be 7 bytes, but they're not the same, and I don't see any obvious pattern (or text encoding).

On a related note, while main_mute('=', ...) always fails, other functions succeed but sometimes return unusual values. For example:

>>> r.main_volume('=', -30)
DEBUG: msg=`b'Main.Volume=-30\r'`
-30.0
>>> r.main_volume('=', -30)
DEBUG: msg=`b"Tuner.FM.RDSName=on Tino'\r"`
>>> r.main_volume('=', -30)
DEBUG: msg=`b''`

I'm happy to run any other tests you can think of.