diff --git a/backend/recorder_adapters/__init__.py b/backend/recorder_adapters/__init__.py index 77656bc..7983e41 100644 --- a/backend/recorder_adapters/__init__.py +++ b/backend/recorder_adapters/__init__.py @@ -76,7 +76,7 @@ class TelnetAdapter(ABC): def _run_cmd(self, cmd, timeout=1, auto_connect=True): if self.tn is None and not auto_connect: - raise Exception("Not connected!") + raise LrcException("Not connected!") elif self.tn is None: self._login() self.tn.write(cmd) diff --git a/backend/recorder_adapters/extron_smp.py b/backend/recorder_adapters/extron_smp.py index aec9822..152d74e 100644 --- a/backend/recorder_adapters/extron_smp.py +++ b/backend/recorder_adapters/extron_smp.py @@ -1,7 +1,9 @@ """ Recorder Adapter for SMP """ +import enum import logging +from typing import Union from backend import LrcException from backend.recorder_adapters import telnetlib, TelnetAdapter, RecorderAdapter @@ -18,29 +20,76 @@ REQUIRES_PW = True # HOST = "129.13.51.102" # Audimax SMP 351 # HOST = "129.13.51.106" # Tulla SMP 351 HOST = "172.22.246.207" # Test SMP MZ -HOST = "129.13.51.109" # Hertz +# HOST = "129.13.51.109" # Hertz USER = "admin" PW = "123mzsmp" # PW = "audimaxsmp" -PW = "smphertz" +# PW = "smphertz" class SMP35x(TelnetAdapter, RecorderAdapter): - def __init__(self, address, password, auto_login=True, **kwargs): + """ + A class representing the Extron SMP recorder. + + Attributes: + AudioChannels (enum.Enum): Enum representing the available audio channels on the Extron SMP recorder. + """ + + class AudioChannels(enum.IntEnum): + """ + Enum representing the available audio channels on the Extron SMP recorder. + + Attributes: + ANALOG_INPUT_A_LEFT (int): The left analog input channel A. + ANALOG_INPUT_A_RIGHT (int): The right analog input channel A. + DIGITAL_INPUT_A_LEFT (int): The left digital input channel A. + DIGITAL_INPUT_A_RIGHT (int): The right digital input channel A. + ANALOG_INPUT_B_LEFT (int): The left analog input channel B. + ANALOG_INPUT_B_RIGHT (int): The right analog input channel B. + DIGITAL_INPUT_B_LEFT (int): The left digital input channel B. + DIGITAL_INPUT_B_RIGHT (int): The right digital input channel B. + OUTPUT_LEFT (int): The left output channel. + OUTPUT_RIGHT (int): The right output channel. + """ + + ANALOG_INPUT_A_LEFT = 40000 + ANALOG_INPUT_A_RIGHT = 40001 + DIGITAL_INPUT_A_LEFT = 40002 + DIGITAL_INPUT_A_RIGHT = 40003 + ANALOG_INPUT_B_LEFT = 40004 + ANALOG_INPUT_B_RIGHT = 40005 + DIGITAL_INPUT_B_LEFT = 40006 + DIGITAL_INPUT_B_RIGHT = 40007 + OUTPUT_LEFT = 60000 + OUTPUT_RIGHT = 60001 + + def __init__(self, address, password, auto_login=True, **_kwargs): + """ + Initializes a new instance of the SMP35x class. + + Args: + address (str): The IP address of the recorder. + password (str): The password for the recorder. + auto_login (bool): Whether to automatically login to the recorder. Defaults to True. + **kwargs: Additional keyword arguments. + """ RecorderAdapter.__init__(self, address, "", password) TelnetAdapter.__init__(self, address) if auto_login: self._login() def _login(self): - logger.debug("Connecting to {} ...".format(self.address)) + """ + Logs in to the recorder. + """ + logger.debug("Connecting to %s ...", self.address) try: self.tn = telnetlib.Telnet(self.address) except TimeoutError as e: - raise LrcException(str(e)) + raise LrcException(str(e)) from e except ConnectionRefusedError as e: - raise LrcException(str(e)) + raise LrcException(str(e)) from e self.tn.read_until("\r\nPassword:") # password = getpass.getpass() password = self.password @@ -52,24 +101,50 @@ class SMP35x(TelnetAdapter, RecorderAdapter): print(out[1]) if "Password:" in out[1]: # TODO: loop until logged in... - logger.warning("Could not login (as admin) with given password! {}".format(self.address)) + logger.warning( + "Could not login (as admin) with given password! %s", self.address + ) print("re-enter pw") self.tn.write(self.password + "\n\r") - print(self.tn.assert_string_in_output("Login Administrator")) - print("WRONG (admin) password!! Exiting!") - print(self.password) + self.tn.assert_string_in_output("Login Administrator") + logger.error("WRONG (admin) password!! Exiting! %s", self.password) self.tn = None - logger.error("Could definitely not login (as admin) with given password! {}".format(self.address)) - raise Exception("Could not login as administrator with given pw!") - print("OK, we have admin rights!") + logger.error( + "Could definitely not login (as admin) with given password! %s", + self.address, + ) + raise LrcException("Could not login as administrator with given pw!") + logger.info("OK, we have admin rights!") def _get_name(self): + """ + Gets the name of the recorder. + + Returns: + str: The name of the recorder. + """ return RECORDER_MODEL_NAME def _get_version(self): + """ + Gets the version of the recorder. + + Returns: + str: The version of the recorder. + """ return VERSION def get_version(self, include_build=False, verbose_info=False): + """ + Gets the version of the recorder. + + Args: + include_build (bool): Whether to include the build number. Defaults to False. + verbose_info (bool): Whether to include verbose information. Defaults to False. + + Returns: + str: The version of the recorder. + """ if verbose_info: self.tn.write("0Q") else: @@ -81,58 +156,142 @@ class SMP35x(TelnetAdapter, RecorderAdapter): return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_bootstrap_version(self): + """ + Gets the bootstrap version of the recorder. + + Returns: + str: The bootstrap version of the recorder. + """ self.tn.write("2Q") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_factory_firmware_version(self): + """ + Gets the factory firmware version of the recorder. + + Returns: + str: The factory firmware version of the recorder. + """ self.tn.write("3Q") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_updated_firmware_version(self): + """ + Gets the updated firmware version of the recorder. + + Returns: + str: The updated firmware version of the recorder. + """ self.tn.write("4Q") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_part_number(self): + """ + Gets the part number of the recorder. + + Returns: + str: The part number of the recorder. + """ self.tn.write("N") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_model_name(self): + """ + Gets the model name of the recorder. + + Returns: + str: The model name of the recorder. + """ self.tn.write("1I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_model_description(self): + """ + Gets the model description of the recorder. + + Returns: + str: The model description of the recorder. + """ self.tn.write("2I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_system_memory_usage(self): + """ + Gets the system memory usage of the recorder. + + Returns: + str: The system memory usage of the recorder. + """ self.tn.write("3I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_number_of_connected_users(self): + """ + Gets the number of connected users to the recorder. + + Returns: + str: The number of connected users to the recorder. + """ self.tn.write("10I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_system_processer_usage(self): + """ + Gets the system processor usage of the recorder. + + Returns: + str: The system processor usage of the recorder. + """ self.tn.write("11I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_system_processor_idle(self): + """ + Gets the system processor idle of the recorder. + + Returns: + str: The system processor idle of the recorder. + """ self.tn.write("12I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_eth0_link_status(self): + """ + Gets the eth0 link status of the recorder. + + Returns: + str: The eth0 link status of the recorder. + """ self.tn.write("13I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_file_transfer_config(self): + """ + Gets the file transfer configuration of the recorder. + + Returns: + str: The file transfer configuration of the recorder. + """ self.tn.write("38I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_active_alarms(self): + """ + Gets the active alarms of the recorder. + + Returns: + str: The active alarms of the recorder. + """ self.tn.write("39I") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_unit_name(self, name: str): + """ + Sets the name of the recorder. + + Args: + name (str): The name of the recorder. + """ # TODO: check name (must comply with internet host name standards) self.tn.write(self.esc_char + name + "CN\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) @@ -160,7 +319,7 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if mode not in range(4): - raise Exception("Only values from 0 to 3 are allowed!") + raise LrcException("Only values from 0 to 3 are allowed!") self.tn.write(self.esc_char + str(mode) + "CV\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) @@ -177,8 +336,8 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if mode not in [0, 2]: - raise Exception("Only values 0 and 2 are allowed!") - self.tn.write(self.esc_char + "1*{}XF\n".format(mode)) + raise LrcException("Only values 0 and 2 are allowed!") + self.tn.write(self.esc_char + f"1*{mode}XF\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def restore_configuration(self, mode: int = 2): @@ -190,8 +349,8 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if mode not in [0, 2]: - raise Exception("Only values 0 and 2 are allowed!") - self.tn.write(self.esc_char + "0*{}XF\n".format(mode)) + raise LrcException("Only values 0 and 2 are allowed!") + self.tn.write(self.esc_char + f"0*{mode}XF\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def reboot(self): @@ -244,7 +403,7 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if mode not in range(4): - raise Exception("Only values from 0 to 3 are allowed!") + raise LrcException("Only values from 0 to 3 are allowed!") self.tn.write(str(mode) + "X\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) @@ -308,16 +467,16 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if input_num not in range(1, 6): - raise Exception("input_num must be a value between 1 and 5!") + raise LrcException("input_num must be a value between 1 and 5!") if channel_num not in range(1, 3): - raise Exception("input_num must be a value between 1 and 2!") - self.tn.write("{}*{}!\n".format(input_num, channel_num)) + raise LrcException("input_num must be a value between 1 and 2!") + self.tn.write(f"{input_num}*{channel_num}!\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_input(self, channel_num: int): if channel_num not in range(1, 2): - raise Exception("input_num must be a value between 1 and 2!") - self.tn.write("{}!\n".format(channel_num)) + raise LrcException("input_num must be a value between 1 and 2!") + self.tn.write(f"{channel_num}!\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_input_format(self, input_num: int, input_format: int): @@ -331,34 +490,34 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if input_num not in range(1, 6): - raise Exception("input_num must be a value between 1 and 5!") + raise LrcException("input_num must be a value between 1 and 5!") if input_format not in range(1, 4): - raise Exception("input_num must be a value between 1 and 3!") - self.tn.write("{}*{}\\\n".format(input_num, input_format)) + raise LrcException("input_num must be a value between 1 and 3!") + self.tn.write(f"{input_num}*{input_format}\\\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_input_format(self, input_num: int): if input_num not in range(1, 6): - raise Exception("input_num must be a value between 1 and 5!") - self.tn.write("{}\\\n".format(input_num)) + raise LrcException("input_num must be a value between 1 and 5!") + self.tn.write(f"{input_num}\\\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_input_name(self, input_num: int, input_name: str): if input_num not in range(1, 6): - raise Exception("input_num must be a value between 1 and 5!") + raise LrcException("input_num must be a value between 1 and 5!") if len(input_name) > 16: - raise Exception("input_name must be no longer than 16 chars") + raise LrcException("input_name must be no longer than 16 chars") try: - input_name.encode('ascii') - except UnicodeEncodeError: - raise Exception("input_name must only contain ascii characters") - self.tn.write("{}{},{}NI\n".format(self.esc_char, input_num, input_name)) + input_name.encode("ascii") + except UnicodeEncodeError as exc: + raise LrcException("input_name must only contain ascii characters") from exc + self.tn.write(f"{self.esc_char}{input_num},{input_name}NI\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_input_name(self, input_num: int): if input_num not in range(1, 6): - raise Exception("input_num must be a value between 1 and 5!") - self.tn.write("{}{}NI\n".format(self.esc_char, input_num)) + raise LrcException("input_num must be a value between 1 and 5!") + self.tn.write(f"{self.esc_char}{input_num}NI\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_input_selction_per_channel(self): @@ -370,15 +529,15 @@ class SMP35x(TelnetAdapter, RecorderAdapter): """ def stop_recording(self): - self.tn.write("{}Y0RCDR\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}Y0RCDR\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def start_recording(self): - self.tn.write("{}Y1RCDR\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}Y1RCDR\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def pause_recording(self): - self.tn.write("{}Y2RCDR\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}Y2RCDR\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) @exception_decorator(ConnectionError) @@ -390,7 +549,7 @@ class SMP35x(TelnetAdapter, RecorderAdapter): 2=pause :return: status """ - self.tn.write("{}YRCDR\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}YRCDR\n") return int(TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())) def is_recording(self) -> bool: @@ -403,12 +562,12 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if extension_time not in range(0, 100): - raise Exception("extension_time must be a value between 0 and 99!") - self.tn.write("{}E{}RCDR\n".format(self.esc_char, extension_time)) + raise LrcException("extension_time must be a value between 0 and 99!") + self.tn.write(f"{self.esc_char}E{extension_time}RCDR\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def add_chapter_marker(self): - self.tn.write("{}BRCDR\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}BRCDR\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def swap_channel_positions(self): @@ -431,89 +590,91 @@ class SMP35x(TelnetAdapter, RecorderAdapter): self.tn.write("37I\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) - """ - Metadata part skipped - """ + ### Metadata part skipped def recall_user_preset(self, channel_number: int, preset_number: int): if channel_number not in range(1, 3): - raise Exception("channel_number must be a value between 1 and 2!") + raise LrcException("channel_number must be a value between 1 and 2!") if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("1*{}*{}.\n".format(channel_number, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"1*{channel_number}*{preset_number}.\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def save_user_preset(self, channel_number: int, preset_number: int): if channel_number not in range(1, 3): - raise Exception("channel_number must be a value between 1 and 2!") + raise LrcException("channel_number must be a value between 1 and 2!") if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("1*{}*{},\n".format(channel_number, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"1*{channel_number}*{preset_number},\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_user_preset_name(self, preset_number: int, preset_name: str): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") + raise LrcException("preset_number must be a value between 1 and 16!") if len(preset_name) > 16: - raise Exception("preset_name must be no longer than 16 chars") + raise LrcException("preset_name must be no longer than 16 chars") try: - preset_name.encode('ascii') - except UnicodeEncodeError: - raise Exception("preset_name must only contain ascii characters") - self.tn.write("{}1*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name)) + preset_name.encode("ascii") + except UnicodeEncodeError as exc: + raise LrcException( + "preset_name must only contain ascii characters" + ) from exc + self.tn.write(f"{self.esc_char}1*{preset_number},{preset_name}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_user_preset_name(self, preset_number: int): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("{}1*{}PNAM\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"{self.esc_char}1*{preset_number}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_user_presets(self, input_number: int): if input_number not in range(1, 6): - raise Exception("input_number must be a value between 1 and 5!") - self.tn.write("52*{}#\n".format(input_number)) + raise LrcException("input_number must be a value between 1 and 5!") + self.tn.write(f"52*{input_number}#\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) # Input Presets def recall_input_preset(self, channel_number: int, preset_number: int): if channel_number not in range(1, 3): - raise Exception("channel_number must be a value between 1 and 2!") + raise LrcException("channel_number must be a value between 1 and 2!") if preset_number not in range(1, 129): - raise Exception("preset_number must be a value between 1 and 128!") - self.tn.write("2*{}*{}.\n".format(channel_number, preset_number)) + raise LrcException("preset_number must be a value between 1 and 128!") + self.tn.write(f"2*{channel_number}*{preset_number}.\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def save_input_preset(self, channel_number: int, preset_number: int): if channel_number not in range(1, 3): - raise Exception("channel_number must be a value between 1 and 2!") + raise LrcException("channel_number must be a value between 1 and 2!") if preset_number not in range(1, 129): - raise Exception("preset_number must be a value between 1 and 128!") - self.tn.write("1*{}*{},\n".format(channel_number, preset_number)) + raise LrcException("preset_number must be a value between 1 and 128!") + self.tn.write(f"1*{channel_number}*{preset_number},\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_input_preset_name(self, preset_number: int, preset_name: str): if preset_number not in range(1, 129): - raise Exception("preset_number must be a value between 1 and 128!") + raise LrcException("preset_number must be a value between 1 and 128!") if len(preset_name) > 16: - raise Exception("preset_name must be no longer than 16 chars") + raise LrcException("preset_name must be no longer than 16 chars") try: - preset_name.encode('ascii') - except UnicodeEncodeError: - raise Exception("preset_name must only contain ascii characters") - self.tn.write("{}2*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name)) + preset_name.encode("ascii") + except UnicodeEncodeError as exc: + raise LrcException( + "preset_name must only contain ascii characters" + ) from exc + self.tn.write(f"{self.esc_char}2*{preset_number},{preset_name}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_input_preset_name(self, preset_number: int): if preset_number not in range(1, 129): - raise Exception("preset_number must be a value between 1 and 128!") - self.tn.write("{}2*{}PNAM\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 128!") + self.tn.write(f"{self.esc_char}2*{preset_number}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def delete_input_preset(self, preset_number: int): if preset_number not in range(1, 129): - raise Exception("preset_number must be a value between 1 and 128!") - self.tn.write("{}X2*{}PRST\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 128!") + self.tn.write(f"{self.esc_char}X2*{preset_number}PRST\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_input_presets(self): @@ -532,10 +693,10 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if output_number not in range(1, 4): - raise Exception("output_number must be a value between 1 and 3!") + raise LrcException("output_number must be a value between 1 and 3!") if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("3*{}*{}.\n".format(output_number, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"3*{output_number}*{preset_number}.\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def save_streaming_preset(self, output_number: int, preset_number: int): @@ -549,34 +710,36 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if output_number not in range(1, 4): - raise Exception("output_number must be a value between 1 and 3!") + raise LrcException("output_number must be a value between 1 and 3!") if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("3*{}*{},\n".format(output_number, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"3*{output_number}*{preset_number},\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_streaming_preset_name(self, preset_number: int, preset_name: str): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") + raise LrcException("preset_number must be a value between 1 and 16!") if len(preset_name) > 16: - raise Exception("preset_name must be no longer than 16 chars") + raise LrcException("preset_name must be no longer than 16 chars") try: - preset_name.encode('ascii') - except UnicodeEncodeError: - raise Exception("preset_name must only contain ascii characters") - self.tn.write("{}3*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name)) + preset_name.encode("ascii") + except UnicodeEncodeError as exc: + raise LrcException( + "preset_name must only contain ascii characters" + ) from exc + self.tn.write(f"{self.esc_char}3*{preset_number},{preset_name}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_streaming_preset_name(self, preset_number: int): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("{}3*{}PNAM\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"{self.esc_char}3*{preset_number}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def reset_streaming_preset_to_default(self, preset_number: int): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("{}X3*{}PRST\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"{self.esc_char}X3*{preset_number}PRST\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) # Encoder Presets @@ -591,10 +754,10 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if output_number not in range(1, 4): - raise Exception("output_number must be a value between 1 and 3!") + raise LrcException("output_number must be a value between 1 and 3!") if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("4*{}*{}.\n".format(output_number, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"4*{output_number}*{preset_number}.\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def save_encoder_preset(self, output_number: int, preset_number: int): @@ -608,80 +771,87 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if output_number not in range(1, 4): - raise Exception("output_number must be a value between 1 and 3!") + raise LrcException("output_number must be a value between 1 and 3!") if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("4*{}*{},\n".format(output_number, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"4*{output_number}*{preset_number},\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_encoder_preset_name(self, preset_number: int, preset_name: str): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") + raise LrcException("preset_number must be a value between 1 and 16!") if len(preset_name) > 16: - raise Exception("preset_name must be no longer than 16 chars") + raise LrcException("preset_name must be no longer than 16 chars") try: - preset_name.encode('ascii') - except UnicodeEncodeError: - raise Exception("preset_name must only contain ascii characters") - self.tn.write("{}4*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name)) + preset_name.encode("ascii") + except UnicodeEncodeError as exc: + raise LrcException( + "preset_name must only contain ascii characters" + ) from exc + self.tn.write(f"{self.esc_char}4*{preset_number},{preset_name}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_encoder_preset_name(self, preset_number: int): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("{}4*{}PNAM\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"{self.esc_char}4*{preset_number}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def reset_encoder_preset_to_default(self, preset_number: int): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("{}X4*{}PRST\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"{self.esc_char}X4*{preset_number}PRST\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) # Layout Presets def save_layout_preset(self, preset_number: int): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("7*{},\n".format(preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"7*{preset_number},\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) - def recall_layout_preset(self, preset_number: int, include_input_selections: bool = True): + def recall_layout_preset( + self, preset_number: int, include_input_selections: bool = True + ): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") + raise LrcException("preset_number must be a value between 1 and 16!") if include_input_selections: - self.tn.write("7*{}.\n".format(preset_number)) + self.tn.write(f"7*{preset_number}.\n") else: - self.tn.write("8*{}.\n".format(preset_number)) + self.tn.write(f"8*{preset_number}.\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_layout_preset_name(self, preset_number: int, preset_name: str): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") + raise LrcException("preset_number must be a value between 1 and 16!") if len(preset_name) > 16: - raise Exception("preset_name must be no longer than 16 chars") + raise LrcException("preset_name must be no longer than 16 chars") try: - preset_name.encode('ascii') - except UnicodeEncodeError: - raise Exception("preset_name must only contain ascii characters") - self.tn.write("{}7*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name)) + preset_name.encode("ascii") + except UnicodeEncodeError as exc: + raise LrcException( + "preset_name must only contain ascii characters" + ) from exc + self.tn.write( + "{}7*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name) + ) return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_layout_preset_name(self, preset_number: int): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("{}7*{}PNAM\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"{self.esc_char}7*{preset_number}PNAM\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def reset_layout_preset_to_default(self, preset_number: int): if preset_number not in range(1, 17): - raise Exception("preset_number must be a value between 1 and 16!") - self.tn.write("{}X7*{}PRST\n".format(self.esc_char, preset_number)) + raise LrcException("preset_number must be a value between 1 and 16!") + self.tn.write(f"{self.esc_char}X7*{preset_number}PRST\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) - """ - Input adjustments skipped - Picture adjustments skipped - """ + ### Input adjustments skipped + + ### Picture adjustments skipped def mute_output(self, output_number: int): """ @@ -692,8 +862,8 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if output_number not in range(1, 3): - raise Exception("output_number must be a value between 1 and 2!") - self.tn.write("{}*1B\n".format(output_number)) + raise LrcException("output_number must be a value between 1 and 2!") + self.tn.write(f"{output_number}*1B\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def unmute_output(self, output_number: int): @@ -705,8 +875,8 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if output_number not in range(1, 3): - raise Exception("output_number must be a value between 1 and 2!") - self.tn.write("{}*0B\n".format(output_number)) + raise LrcException("output_number must be a value between 1 and 2!") + self.tn.write(f"{output_number}*0B\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def is_muted(self, output_number: int): @@ -718,20 +888,22 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if output_number not in range(1, 3): - raise Exception("output_number must be a value between 1 and 2!") - self.tn.write("{}B\n".format(output_number)) - return int(TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())) > 0 + raise LrcException("output_number must be a value between 1 and 2!") + self.tn.write(f"{output_number}B\n") + return ( + int(TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())) + > 0 + ) - """ - EDID skipped - Encoder settings skipped - some advanced options skipped - """ + ### EDID skipped + + ### Encoder settings skipped + + ### some advanced options skipped @classmethod def get_recorder_params(cls) -> dict: - return {'_requires_user': False, - '_requires_password': True} + return {"_requires_user": False, "_requires_password": True} def get_input_hdcp_status(self, input_number: int): """ @@ -743,53 +915,90 @@ class SMP35x(TelnetAdapter, RecorderAdapter): :return: """ if input_number not in range(1, 6): - raise Exception("input_number must be a value between 1 and 6!") - self.tn.write("{}I{}HDCP\n".format(self.esc_char, input_number)) + raise LrcException("input_number must be a value between 1 and 6!") + self.tn.write(f"{self.esc_char}I{input_number}HDCP\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_input_authorization_hdcp_on(self, input_number: int): if input_number not in range(1, 6): - raise Exception("input_number must be a value between 1 and 6!") - self.tn.write("{}E{}*1HDCP\n".format(self.esc_char, input_number)) + raise LrcException("input_number must be a value between 1 and 6!") + self.tn.write(f"{self.esc_char}E{input_number}*1HDCP\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def set_input_authorization_hdcp_off(self, input_number: int): if input_number not in range(1, 6): - raise Exception("input_number must be a value between 1 and 6!") - self.tn.write("{}E{}*0HDCP\n".format(self.esc_char, input_number)) + raise LrcException("input_number must be a value between 1 and 6!") + self.tn.write(f"{self.esc_char}E{input_number}*0HDCP\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_input_authorization_hdcp_status(self, input_number: int): if input_number not in range(1, 6): - raise Exception("input_number must be a value between 1 and 6!") - self.tn.write("{}E{}HDCP\n".format(self.esc_char, input_number)) + raise LrcException("input_number must be a value between 1 and 6!") + self.tn.write(f"{self.esc_char}E{input_number}HDCP\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def enable_hdcp_notification(self): - self.tn.write("{}N1HDCP\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}N1HDCP\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def disable_hdcp_notification(self): - self.tn.write("{}N0HDCP\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}N0HDCP\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_hdcp_notification_status(self): - self.tn.write("{}NHDCP\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}NHDCP\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) # background image settings def set_background_image(self, filename: str): - self.tn.write("{}{}RF\n".format(self.esc_char, filename)) + self.tn.write(f"{self.esc_char}{filename}RF\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def get_background_image_filename(self): - self.tn.write("{}RF\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}RF\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) def mute_background_image(self): - self.tn.write("{}0RF\n".format(self.esc_char)) + self.tn.write(f"{self.esc_char}0RF\n") return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) + # Audio settings + def _get_audio_channel_number( + self, channel_number: Union["SMP35x.AudioChannels", int] + ): + if isinstance(channel_number, SMP35x.AudioChannels): + return channel_number.value + elif isinstance(channel_number, int): + if channel_number in iter(SMP35x.AudioChannels): + return channel_number + raise ValueError( + f"channel_number must be a SMP35x.AudioChannels or one of " + f"{','.join([str(x.value) for x in iter(SMP35x.AudioChannels)])}, " + f"but was {channel_number}" + ) + else: + raise TypeError("channel_number must be a SMP35x.AudioChannels or int") + + def mute_audio_channel(self, channel_number: Union["SMP35x.AudioChannels", int]): + num = self._get_audio_channel_number(channel_number) + self.tn.write(f"{self.esc_char}M{num}*1AU\n") + return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) + + def unmute_audio_channel(self, channel_number: Union["SMP35x.AudioChannels", int]): + num = self._get_audio_channel_number(channel_number) + self.tn.write(f"{self.esc_char}M{num}*0AU\n") + return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) + + def is_audio_channel_muted( + self, channel_number: Union["SMP35x.AudioChannels", int] + ): + num = self._get_audio_channel_number(channel_number) + self.tn.write(f"{self.esc_char}M{num}AU\n") + return ( + int(TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())) + > 0 + ) + def main(): smp = SMP35x(HOST, PW, True) @@ -797,6 +1006,11 @@ def main(): print(smp) print(smp.get_recording_status()) print(smp.is_recording()) + print(smp.is_muted(1)) + print(smp.is_muted(2)) + print(smp.is_audio_channel_muted(SMP35x.AudioChannels.ANALOG_INPUT_A_LEFT)) + print(smp.is_audio_channel_muted(SMP35x.AudioChannels.DIGITAL_INPUT_A_LEFT)) + print(smp.is_audio_channel_muted(60000)) exit() smp._login() @@ -841,5 +1055,5 @@ def main(): print(smp.is_muted(2)) -if __name__ == '__main__': +if __name__ == "__main__": main()