Package: rsp1570serial-pp81381
rsp1570serialAn asyncio based package to talk to a Rotel RSP-1570 processor using the RS-232 protocolSeethis documentfor the protocol definitionKnown to work with a GANA USB to RS-232 DB9 cable on Windows 10 and on Raspbian StretchThe protocol is similar to that used by other older Rotel kit.   For example, it looks as though the RSP-1572 used a protocol like this.  It has a different device id and supports a few more messages but this package could probably be updated to support it.This library was built to support a rotel_rsp1570 media player platform entity forHome Assistantthat can be foundhere.UsageCreate a connnectionThe connection objects encapsulate most of the functionality of the library.It is recommended that theSharedRotelAmpConnis used in preference to the basicRotelAmpConn.  Either way, use the context manager factory methods to create a connection.  E.g.:fromrsp1570serial.connectionimportcreate_shared_rotel_amp_connfromrsp1570serial.utilsimportget_platform_serial_portasyncdefdo_something(serial_port=None):ifserial_portisNone:serial_port=get_platform_serial_port()asyncwithcreate_shared_rotel_amp_conn(serial_port)asshared_conn:conn=shared_conn.new_client_conn()# Do something hereThe serial_port parameter can be anything that can be passed toserial.serial_for_url().  E.g./dev/ttyUSB0(Linux)COM3(Windows)socket://192.168.0.100:50000(if you are using a TCP/IP to serial  converter)An exception of typeRotelAmpConnConnectionErroris thrown if a connection cannot be made to the specified device.send_command(command_code)Send a command (seecommands.pyfor the full list):awaitconn.send_command('MUTE_TOGGLE')send_volume_direct_command(zone, volume)Send a volume direct command to a zone:fromrsp1570serial.commandsimportMIN_VOLUME,MAX_VOLUMEzone=1awaitconn.send_volume_direct_command(zone,MAX_VOLUME)awaitasyncio.sleep(1)awaitconn.send_volume_direct_command(zone,MIN_VOLUME)awaitasyncio.sleep(1)awaitconn.send_volume_direct_command(zone,50)read_messages()Read the input stream from the device:asyncformessageinconn.read_messages():if(isinstance(message,(FeedbackMessage,TriggerMessage))):message.log()else:logging.warning("Unknown message type encountered")conn.process_command(command_code, time_window=DEFAULT_TIME_WINDOW)Send a command and then collect all messages that arrive intime_window.  Class constants are provided with recommended time windows.   Note that the 'POWER_ON' command needs a longer time window than other commands.asyncwithcreate_test_shared_conn()asshared_conn:conn=shared_conn.new_client_conn()messages=awaitconn.process_command('POWER_ON',conn.POWER_ON_TIME_WINDOW)This command can be handy for scripting-like automations.   Seediscovery.pyfor an example.MessagesTheconn.read_messages()andconn.process_command()methods will return a message-type specific object containing the message data.  Two types of message can be encountered:FeedbackMessage: Reflects what is shown on the front-panel display.   Received when the display changes.TriggerMessage: Received whenever the 12V triggers change state.Source AliasesThe user of a Rotel Amplifier can customise the name shown on the display for each source.   These 'aliases' are the names that will be found in thesource_namefield of theFeedbackMessagerather than the official source names.  For example, a user might configure the name of the 'VIDEO 1' source to be 'CATV'.  In this instance, the client software would need to know to send the 'SOURCE_VIDEO_1'command_codein order to select the source that the user knows as 'CATV'.discover_source_aliases(serial_port)This is a utility function that can be used by Home Automation software to discover the aliases for all of the sources.   It returns a dictionary that maps each source alias to thecommand_codeneeded to switch to that source.   The discovery process is not quick so it is recommended to use this utility in the initial device configuration rather than each time the Home Automation software is started.source_map=awaitdiscover_source_aliases(serial_port)self.assertDictEqual(source_map,{'CATV':'SOURCE_VIDEO_1','NMT':'SOURCE_VIDEO_2','APPLE TV':'SOURCE_VIDEO_3','FIRE TV':'SOURCE_VIDEO_4','BLU RAY':'SOURCE_VIDEO_5','TUNER':'SOURCE_TUNER','TAPE':'SOURCE_TAPE','MULTI':'SOURCE_MULTI_INPUT',' CD':'SOURCE_CD'})ExamplesPlease see example1.py and example2.py and the test suite for fully working examples.ObjectsRotelAmpConnThe RotelAmpConn object is the basic connection object.   It can be used to establish a single, dedicated connection to the device, send commands and read responses.  Consider usingSharedRotelAmpConnin preference to this lower level object.Use thecreate_rotel_amp_conncontext manager as a factory:fromrsp1570serial.connectionimportcreate_rotel_amp_connfromrsp1570serial.utilsimportget_platform_serial_portasyncdefdo_something(serial_port=None):ifserial_portisNone:serial_port=get_platform_serial_port()asyncwithcreate_rotel_amp_conn(serial_port)asconn:# Do something hereMethodDescriptioncreate_rotel_amp_conn(serial_port)Context manager to create and open a connectionconn.send_command(command_code)Send a command (seecommands.pyfor the full list)conn.send_volume_direct_command(zone, volume)Set the absolute volume in a zoneconn.read_messages()Iterator that reads the messages from the device.   Seeread_messagesfor more information.SharedRotelAmpConnWraps aRotelAmpConnobject and allows it to be shared.Use thecreate_shared_rotel_amp_conncontext manager as a factory:importasynciofromrsp1570serial.connectionimportcreate_shared_rotel_amp_connfromrsp1570serial.utilsimportget_platform_serial_portasyncdefdo_something(serial_port=None):ifserial_portisNone:serial_port=get_platform_serial_port()asyncwithcreate_shared_rotel_amp_conn(serial_port)asshared_conn:logger_conn=shared_conn.new_client_conn()logger_task=asyncio.create_task(do_something_else(logger_conn))cmd_conn=shared_conn.new_client_conn()awaitcmd_conn.process_command('POWER_ON',conn.POWER_ON_TIME_WINDOW)awaitcmd_conn.process_command('SOURCE_VIDEO_1')awaitcmd_conn.process_command('VOLUME_UP')awaitlogger_taskasyncdeflog_all_messages(conn):asyncformessageinconn.read_messages():message.log()MethodDescriptioncreate_shared_rotel_amp_conn(serial_port)Context manager to create and open a shared connectionshared_conn.new_client_conn()Create a new client connection of typeSharedRotelAmpClientConnSharedRotelAmpClientConnA client connection.   Supports sending commands and receiving messages.  Also supports a mechanism to send a command and collect all of the messages received in a time window, which can be useful for script-like automation of the amplifier.If the client code is not consuming messages from the connection then they will be queued up internally until one of the message consuming methods is called.  Two client connections of the same shared connection are completely independent and can be read at different speeds without back pressure.When finished with the object, simply dereference it and it will be garbage collected.MethodDescriptionconn.send_command(command_code)Send a command (seecommands.pyfor the full list)conn.send_volume_direct_command(zone, volume)Set the absolute volume in a zoneconn.read_messages()Iterator that reads the messages from the device.   Seeread_messagesfor more information.conn.collect_messages()Collect all internally queued messages (emptying the queue)conn.process_command(command_code, time_window=DEFAULT_TIME_WINDOW)Send a command and then collect all messages that arrive intime_window.   See constants below for recommended time windows.ConstantDescriptionconn.POWER_ON_TIME_WINDOWRecommendedtime_windowto be used after a 'POWER_ON' commandconn.DEFAULT_TIME_WINDOWRecommendedtime_windowto be used after most commandsFeedbackMessageThis message reflects what is shown on the display of the device and will be recieved whenever the display changes.   This would typically be after an RS-232 or InfraRed command has been received or after a front panel button has been pressed.The object has 3 properties:PropertyTypeDescriptionmsg.linestwo element listThe two lines of the displaymsg.flagsbytesFlags representing the state of the icons on the displaymsg.iconsdict of str:boolA dictionary keyed on icon code reflecting the on/off state of each iconMethods of interest are:MethodDescriptionmsg.icons_that_are_on()Returns a list of the icon codes of any display icons that are on.   Primarily used for testing and debugging.msg.parse_display_lines()Parse the display lines and return as much as we can infer about the state of the amp in a dict.The following table shows the contents of the dict returned by theparse_display_lines()method.KeyDescriptionis_onOn flag (bool)source_nameSource Name (max. 8 characters)volumeVolume (int)mute_onMute On Flag (bool),party_mode_onParty Mode Flag (bool)infoDisplay Line 2The following table shows all of the icon codes.CodeNameCategoryFriendly NameArsp1570_input_analoginput_iconsAnalog5rsp1570_input_5input_iconsInput 54rsp1570_input_4input_iconsInput 43rsp1570_input_3input_iconsInput 32rsp1570_input_2input_iconsInput 21rsp1570_input_1input_iconsInput 1Coaxialrsp1570_input_coaxialinput_iconsCoaxialOpticalrsp1570_input_opticalinput_iconsOpticalHDMIrsp1570_input_hdmiinput_iconsHDMIPro Logicrsp1570_sound_mode_pro_logicsound_mode_iconsPro LogicIIrsp1570_sound_mode_iisound_mode_iconsIIxrsp1570_sound_mode_xsound_mode_iconsxDolby Digitalrsp1570_sound_mode_dolby_digitalsound_mode_iconsDolby DigitalEXrsp1570_sound_mode_exsound_mode_iconsEXdtsrsp1570_sound_mode_dtssound_mode_iconsdtsESrsp1570_sound_mode_essound_mode_iconsES7.1rsp1570_sound_mode_71sound_mode_icons7.15.1rsp1570_sound_mode_51sound_mode_icons5.1Display Mode0rsp1570_state_display_mode0state_iconsDisplay Mode 0Display Mode1rsp1570_state_display_mode1state_iconsDisplay Mode 1Standby LEDrsp1570_state_standby_ledstate_iconsStandby LEDZone 2rsp1570_state_zone2state_iconsZone 2Zone 3rsp1570_state_zone3state_iconsZone 3Zone 4rsp1570_state_zone4state_iconsZone 4Zonersp1570_state_zonestate_iconsZoneFRrsp1570_speaker_front_rightspeaker_iconsFront RightCrsp1570_speaker_centerspeaker_iconsCenterFLrsp1570_speaker_front_leftspeaker_iconsFront LeftSWrsp1570_speaker_subwooferspeaker_iconsSubwooferSRrsp1570_speaker_surround_rightspeaker_iconsSurround RightSLrsp1570_speaker_surround_leftspeaker_iconsSurround LeftCBLrsp1570_speaker_center_back_leftspeaker_iconsCenter Back LeftCBRrsp1570_speaker_center_back_rightspeaker_iconsCenter Back RightSBrsp1570_speaker_center_backspeaker_iconsCenter Back<rsp1570_misc_ltmisc_iconsMisc <>rsp1570_misc_gtmisc_iconsMisc >TriggerMessageThis object has one property calledflagsof typebytesthat reflects the state of the 12V triggers by zone.The methodflags_to_list()returns a list of the following form:[['All',['on','off','off','off','off','off']],['Main',['on','off','off','off','off','off']],['Zone 2',['off','off','off','off','off','off']],['Zone 3',['off','off','off','off','off','off']],['Zone 4',['off','off','off','off','off','off']],]EmulatorThe package also includes an RSP-1570 emulator that can be used for demonstration or testing purposes.   It can also be used in Home Assistant with the rotel_rsp1570 media player platform.Examples of usage:# Start the emulator on port 50000
python3 -m rsp1570serial.emulator

# Start the emulator on port 50002
python3 -m rsp1570serial.emulator -p 50002

# Start the emulator on port 50002 and provide aliases for some of the sources
python3 -m rsp1570serial.emulator -p 50002 --alias_video_1  CATV --alias_video_2 NMT --alias_video_3 "APPLE TV" --alias_video_4 "FIRE TV" --alias_video_5 "BLU RAY"

# Start the emulator in the on state
python3 -m rsp1570serial.emulator --is_onFull list of options:OptionDescription-p <num>or--port <num>Port number-oor--is_onIf set then the emulator will be turned on initially--cd <str>or--alias_cd <str>Alias for the CD source--tape <str>or--alias_tape <str>Alias for the TAPE source--tuner <str>or--alias_tuner <str>Alias for the TUNER source--video_1 <str>or--alias_video_1 <str>Alias for the VIDEO 1 source--video_2 <str>or--alias_video_2 <str>Alias for the VIDEO 2 source--video_3 <str>or--alias_video_3 <str>Alias for the VIDEO 3 source--video_4 <str>or--alias_video_4 <str>Alias for the VIDEO 4 source--video_5 <str>or--alias_video_5 <str>Alias for the VIDEO 5 source--multi <str>or--alias_multi <str>Alias for the MULTI source