pycti.channel_interface API documentation

# Module `pycti.channel_interface`

Expand source code

    import logging
    import os
    from pydantic import BaseModel
    from pydantic import validator
    from .messages import Msg

    from .cycler_interface import CyclerInterface

    logger = logging.getLogger(__name__)

    class ChannelInterface(CyclerInterface):
        """
        Class for interfacing with Arbin battery cycler at a channel level.
        """

        def __init__(self, config: dict, env_path: str = os.path.join(os.getcwd(), '.env')):
            """
            Creates a class instance for interfacing with Arbin battery cycler at a channel level.

            Parameters
            ----------
            config : dict
                A configuration dictionary. Must contain the following keys:
                    channel : int
                        The channel to target with the ChannelInterface class instance.
                    test_name : *optional* : str
                        The test name to use if using the ChannelInterface to start a test.
                    schedule_name : *optional* : str
                        The name of the schedule file to use if using the ChannelInterface to start a test.
                    ip_address : str
                        The IP address of the Arbin host computer.
                    port : int
                        The TCP port to communicate through.
                    timeout_s : *optional* : float
                        How long to wait before timing out on TCP communication. Defaults to 3 seconds.
                    msg_buffer_size : *optional* : int
                        How big of a message buffer to use for sending/receiving messages.
                        A minimum of 1024 bytes is recommended. Defaults to 4096 bytes.
            env_path : *optional* : str
                The path to the `.env` file containing the Arbin CTI username,`ARBIN_CTI_USERNAME`, and password, `ARBIN_CTI_PASSWORD`.
                Defaults to looking in the working directory.
            """
            self.__config = ChannelInterfaceConfig(**config)
            super().__init__(self.__config.dict(), env_path)

        def read_channel_status(self) -> dict:
            """
            Method to read the status of the channel defined in the config.

            Returns
            -------
            status : dict
                A dictionary detailing the status of the channel. Returns None if there is an issue.
            """
            # Add to channel value to account for zero indexing subtraction in parent method.
            return super().read_channel_status(channel=(self.__config.channel+1))

        def assign_schedule(self) -> bool:
            """
            Method to assign a schedule to the channel defined in the config.

            Returns
            -------
            success : bool
                True/False based on whether the schedule was assigned without issue.
            """
            success = False

            if not self.__config.schedule_name:
                logger.error("Schedule name undefined!")
                return success

            assign_schedule_msg_tx_bin = Msg.AssignSchedule.Client.pack(
                {'channel': self.__config.channel, 'schedule': self.__config.schedule_name})
            response_msg_bin = self._send_receive_msg(
                assign_schedule_msg_tx_bin)

            if response_msg_bin:
                assign_schedule_msg_rx_dict = Msg.AssignSchedule.Server.unpack(
                    response_msg_bin)
                if assign_schedule_msg_rx_dict['result'] == 'success':
                    success = True
                    logger.info(
                        f'Successfully assigned schedule {self.__config.schedule_name} to channel {self.__config.channel}')
                    logger.debug(assign_schedule_msg_rx_dict)
                else:
                    logger.error(
                        f'Failed to assign schedule {self.__config.schedule_name}! Issue: {assign_schedule_msg_rx_dict["result"]}')

            return success

        def start_test(self) -> bool:
            """
            Starts channel on method specified in config.

            Returns
            -------
            success : bool
                True/False based on whether the test was started without issue.
            """
            success = False

            if not self.__config.test_name:
                logger.error("Test name undefined!")
                return success

            # Make sure the schedule is assigned before starting the test to avoid any funny business
            if self.assign_schedule():
                start_test_msg_tx_bin = Msg.StartSchedule.Client.pack(
                    {'channel': self.__config.channel, 'test_name': self.__config.test_name})
                response_msg_bin = self._send_receive_msg(start_test_msg_tx_bin)

                if response_msg_bin:
                    start_test_msg_rx_dict = Msg.StartSchedule.Server.unpack(
                        response_msg_bin)
                    if start_test_msg_rx_dict['result'] == 'success':
                        success = True
                        logger.info(
                            f'Successfully started test {self.__config.test_name} with schedule {self.__config.schedule_name} on channel {self.__config.channel}')
                        logger.debug(start_test_msg_rx_dict)
                    else:
                        logger.error(
                            f'Failed to start test {self.__config.test_name} with schedule {self.__config.schedule_name} on channel {self.__config.channel}. Issue: {start_test_msg_rx_dict["result"]}')

            return success

        def stop_test(self) -> bool:
            """
            Stops the test running on the channel specified in the config.

            Returns
            -------
            success : bool
                True/False based on whether the test stopped without issue.
                Also returns True if no test was running on the channel.
            """
            success = False

            stop_test_msg_tx_bin = Msg.StopSchedule.Client.pack(
                {'channel': self.__config.channel})
            response_msg_bin = self._send_receive_msg(
                stop_test_msg_tx_bin)

            if response_msg_bin:
                stop_test_msg_rx_dict = Msg.StopSchedule.Server.unpack(
                    response_msg_bin)
                if stop_test_msg_rx_dict['result'] == 'success':
                    success = True
                    logger.info(
                        f'Successfully stopped test on channel {self.__config.channel}')
                    logger.debug(stop_test_msg_rx_dict)
                else:
                    logger.error(
                        f'Failed to stop test on channel {self.__config.channel}! Issue: {stop_test_msg_rx_dict["result"]}')

            return success

        def set_meta_variable(self, mv_num: int, mv_value: float) -> bool:
            """
            Sets the passed meta variable number `mv_num` to the passed value `mv_value`
            on the channel specified in the config. Note the test must be running.

            Parameters
            ----------
            mv_num : int
                The meta variable number to set. Must be between 1 and 16 (inclusive)
            mv_value : float
                The meta variable value to set.
            Returns
            -------
            success : bool
                True/False based on whether the meta variable was set.
            """
            success = False

            updated_msg_vals = {}
            updated_msg_vals['channel'] = self.__config.channel
            updated_msg_vals['mv_meta_code'] = Msg.SetMetaVariable.Client.mv_channel_codes[mv_num]
            updated_msg_vals['mv_data'] = mv_value

            set_mv_msg_tx_bin = Msg.SetMetaVariable.Client.pack(updated_msg_vals)
            response_msg_bin = self._send_receive_msg(
                set_mv_msg_tx_bin)

            if response_msg_bin:
                set_mv_msg_rx_dict = Msg.SetMetaVariable.Server.unpack(
                    response_msg_bin)
                if set_mv_msg_rx_dict['result'] == 'success':
                    success = True
                    logger.info(
                        f'Successfully set meta variable {mv_num} to a value of {mv_value}')
                    logger.debug(set_mv_msg_rx_dict)
                else:
                    logger.error(
                        f'Failed to set meta variable {mv_num} to a value of {mv_value}! Issue: {set_mv_msg_rx_dict["result"]}')

            return success

    class ChannelInterfaceConfig(BaseModel):
        '''
        Holds channel config information for the CyclerInterface class.

        Parameters
        ----------
            channel : int
                The channel to target with the ChannelInterface class instance.
            test_name : *optional*
                The test name to use if using the ChannelInterface to start a test.
            schedule_name : str
                The name of the schedule file to use if using the ChannelInterface to start a test.
            ip_address : str
                The IP address of the Arbin host computer.
            port : int
                The TCP port to communicate through.
            timeout_s : float
                How long to wait before timing out on TCP communication. Defaults to 3 seconds.
            msg_buffer_size : int
                 How big of a message buffer to use for sending/receiving messages.
                A minimum of 1024 bytes is recommended. Defaults to 4096 bytes.
        '''
        channel: int
        test_name: str = None
        schedule_name: str = None
        ip_address: str
        port: int
        timeout_s: float = 3.0
        msg_buffer_size: int = 4096

        @validator('channel')
        def username_alphanumeric(cls, v):
            if v < 1:
                raise ValueError('Channel must be greater than zero!')
            return v-1

## Classes

`class ChannelInterface (config: dict, env_path: str = '/Users/zander/Documents/Work/BattGenie/pycti/.env')`

  Class for interfacing with Arbin battery cycler at a channel level.

  Creates a class instance for interfacing with Arbin battery cycler at a channel level.

  ## Parameters

  `config` :`dict`
    A configuration dictionary. Must contain the following keys: channel : int The channel to target with the ChannelInterface class instance. test_name : optional : str The test name to use if using the ChannelInterface to start a test. schedule_name : optional : str The name of the schedule file to use if using the ChannelInterface to start a test. ip_address : str The IP address of the Arbin host computer. port : int The TCP port to communicate through. timeout_s : optional : float How long to wait before timing out on TCP communication. Defaults to 3 seconds. msg_buffer_size : optional : int How big of a message buffer to use for sending/receiving messages. A minimum of 1024 bytes is recommended. Defaults to 4096 bytes.
  `env_path` :`*optional* : str`
    The path to the `.env` file containing the Arbin CTI username,`ARBIN_CTI_USERNAME`, and password, `ARBIN_CTI_PASSWORD`. Defaults to looking in the working directory.
  Expand source code

      class ChannelInterface(CyclerInterface):
          """
          Class for interfacing with Arbin battery cycler at a channel level.
          """

          def __init__(self, config: dict, env_path: str = os.path.join(os.getcwd(), '.env')):
              """
              Creates a class instance for interfacing with Arbin battery cycler at a channel level.

              Parameters
              ----------
              config : dict
                  A configuration dictionary. Must contain the following keys:
                      channel : int
                          The channel to target with the ChannelInterface class instance.
                      test_name : *optional* : str
                          The test name to use if using the ChannelInterface to start a test.
                      schedule_name : *optional* : str
                          The name of the schedule file to use if using the ChannelInterface to start a test.
                      ip_address : str
                          The IP address of the Arbin host computer.
                      port : int
                          The TCP port to communicate through.
                      timeout_s : *optional* : float
                          How long to wait before timing out on TCP communication. Defaults to 3 seconds.
                      msg_buffer_size : *optional* : int
                          How big of a message buffer to use for sending/receiving messages.
                          A minimum of 1024 bytes is recommended. Defaults to 4096 bytes.
              env_path : *optional* : str
                  The path to the `.env` file containing the Arbin CTI username,`ARBIN_CTI_USERNAME`, and password, `ARBIN_CTI_PASSWORD`.
                  Defaults to looking in the working directory.
              """
              self.__config = ChannelInterfaceConfig(**config)
              super().__init__(self.__config.dict(), env_path)

          def read_channel_status(self) -> dict:
              """
              Method to read the status of the channel defined in the config.

              Returns
              -------
              status : dict
                  A dictionary detailing the status of the channel. Returns None if there is an issue.
              """
              # Add to channel value to account for zero indexing subtraction in parent method.
              return super().read_channel_status(channel=(self.__config.channel+1))

          def assign_schedule(self) -> bool:
              """
              Method to assign a schedule to the channel defined in the config.

              Returns
              -------
              success : bool
                  True/False based on whether the schedule was assigned without issue.
              """
              success = False

              if not self.__config.schedule_name:
                  logger.error("Schedule name undefined!")
                  return success

              assign_schedule_msg_tx_bin = Msg.AssignSchedule.Client.pack(
                  {'channel': self.__config.channel, 'schedule': self.__config.schedule_name})
              response_msg_bin = self._send_receive_msg(
                  assign_schedule_msg_tx_bin)

              if response_msg_bin:
                  assign_schedule_msg_rx_dict = Msg.AssignSchedule.Server.unpack(
                      response_msg_bin)
                  if assign_schedule_msg_rx_dict['result'] == 'success':
                      success = True
                      logger.info(
                          f'Successfully assigned schedule {self.__config.schedule_name} to channel {self.__config.channel}')
                      logger.debug(assign_schedule_msg_rx_dict)
                  else:
                      logger.error(
                          f'Failed to assign schedule {self.__config.schedule_name}! Issue: {assign_schedule_msg_rx_dict["result"]}')

              return success

          def start_test(self) -> bool:
              """
              Starts channel on method specified in config.

              Returns
              -------
              success : bool
                  True/False based on whether the test was started without issue.
              """
              success = False

              if not self.__config.test_name:
                  logger.error("Test name undefined!")
                  return success

              # Make sure the schedule is assigned before starting the test to avoid any funny business
              if self.assign_schedule():
                  start_test_msg_tx_bin = Msg.StartSchedule.Client.pack(
                      {'channel': self.__config.channel, 'test_name': self.__config.test_name})
                  response_msg_bin = self._send_receive_msg(start_test_msg_tx_bin)

                  if response_msg_bin:
                      start_test_msg_rx_dict = Msg.StartSchedule.Server.unpack(
                          response_msg_bin)
                      if start_test_msg_rx_dict['result'] == 'success':
                          success = True
                          logger.info(
                              f'Successfully started test {self.__config.test_name} with schedule {self.__config.schedule_name} on channel {self.__config.channel}')
                          logger.debug(start_test_msg_rx_dict)
                      else:
                          logger.error(
                              f'Failed to start test {self.__config.test_name} with schedule {self.__config.schedule_name} on channel {self.__config.channel}. Issue: {start_test_msg_rx_dict["result"]}')

              return success

          def stop_test(self) -> bool:
              """
              Stops the test running on the channel specified in the config.

              Returns
              -------
              success : bool
                  True/False based on whether the test stopped without issue.
                  Also returns True if no test was running on the channel.
              """
              success = False

              stop_test_msg_tx_bin = Msg.StopSchedule.Client.pack(
                  {'channel': self.__config.channel})
              response_msg_bin = self._send_receive_msg(
                  stop_test_msg_tx_bin)

              if response_msg_bin:
                  stop_test_msg_rx_dict = Msg.StopSchedule.Server.unpack(
                      response_msg_bin)
                  if stop_test_msg_rx_dict['result'] == 'success':
                      success = True
                      logger.info(
                          f'Successfully stopped test on channel {self.__config.channel}')
                      logger.debug(stop_test_msg_rx_dict)
                  else:
                      logger.error(
                          f'Failed to stop test on channel {self.__config.channel}! Issue: {stop_test_msg_rx_dict["result"]}')

              return success

          def set_meta_variable(self, mv_num: int, mv_value: float) -> bool:
              """
              Sets the passed meta variable number `mv_num` to the passed value `mv_value`
              on the channel specified in the config. Note the test must be running.

              Parameters
              ----------
              mv_num : int
                  The meta variable number to set. Must be between 1 and 16 (inclusive)
              mv_value : float
                  The meta variable value to set.
              Returns
              -------
              success : bool
                  True/False based on whether the meta variable was set.
              """
              success = False

              updated_msg_vals = {}
              updated_msg_vals['channel'] = self.__config.channel
              updated_msg_vals['mv_meta_code'] = Msg.SetMetaVariable.Client.mv_channel_codes[mv_num]
              updated_msg_vals['mv_data'] = mv_value

              set_mv_msg_tx_bin = Msg.SetMetaVariable.Client.pack(updated_msg_vals)
              response_msg_bin = self._send_receive_msg(
                  set_mv_msg_tx_bin)

              if response_msg_bin:
                  set_mv_msg_rx_dict = Msg.SetMetaVariable.Server.unpack(
                      response_msg_bin)
                  if set_mv_msg_rx_dict['result'] == 'success':
                      success = True
                      logger.info(
                          f'Successfully set meta variable {mv_num} to a value of {mv_value}')
                      logger.debug(set_mv_msg_rx_dict)
                  else:
                      logger.error(
                          f'Failed to set meta variable {mv_num} to a value of {mv_value}! Issue: {set_mv_msg_rx_dict["result"]}')

              return success

  ### Ancestors

  - CyclerInterface

  ### Methods

  `def assign_schedule(self) ‑> bool`

    Method to assign a schedule to the channel defined in the config.

    ## Returns

    `success` :`bool`
      True/False based on whether the schedule was assigned without issue.
    Expand source code

        def assign_schedule(self) -> bool:
            """
            Method to assign a schedule to the channel defined in the config.

            Returns
            -------
            success : bool
                True/False based on whether the schedule was assigned without issue.
            """
            success = False

            if not self.__config.schedule_name:
                logger.error("Schedule name undefined!")
                return success

            assign_schedule_msg_tx_bin = Msg.AssignSchedule.Client.pack(
                {'channel': self.__config.channel, 'schedule': self.__config.schedule_name})
            response_msg_bin = self._send_receive_msg(
                assign_schedule_msg_tx_bin)

            if response_msg_bin:
                assign_schedule_msg_rx_dict = Msg.AssignSchedule.Server.unpack(
                    response_msg_bin)
                if assign_schedule_msg_rx_dict['result'] == 'success':
                    success = True
                    logger.info(
                        f'Successfully assigned schedule {self.__config.schedule_name} to channel {self.__config.channel}')
                    logger.debug(assign_schedule_msg_rx_dict)
                else:
                    logger.error(
                        f'Failed to assign schedule {self.__config.schedule_name}! Issue: {assign_schedule_msg_rx_dict["result"]}')

            return success

  `def read_channel_status(self) ‑> dict`

    Method to read the status of the channel defined in the config.

    ## Returns

    `status` :`dict`
      A dictionary detailing the status of the channel. Returns None if there is an issue.
    Expand source code

        def read_channel_status(self) -> dict:
            """
            Method to read the status of the channel defined in the config.

            Returns
            -------
            status : dict
                A dictionary detailing the status of the channel. Returns None if there is an issue.
            """
            # Add to channel value to account for zero indexing subtraction in parent method.
            return super().read_channel_status(channel=(self.__config.channel+1))

  `def set_meta_variable(self, mv_num: int, mv_value: float) ‑> bool`

    Sets the passed meta variable number `mv_num` to the passed value `mv_value` on the channel specified in the config. Note the test must be running.

    ## Parameters

    `mv_num` :`int`
      The meta variable number to set. Must be between 1 and 16 (inclusive)
    `mv_value` :`float`
      The meta variable value to set.

    ## Returns

    `success` :`bool`
      True/False based on whether the meta variable was set.
    Expand source code

        def set_meta_variable(self, mv_num: int, mv_value: float) -> bool:
            """
            Sets the passed meta variable number `mv_num` to the passed value `mv_value`
            on the channel specified in the config. Note the test must be running.

            Parameters
            ----------
            mv_num : int
                The meta variable number to set. Must be between 1 and 16 (inclusive)
            mv_value : float
                The meta variable value to set.
            Returns
            -------
            success : bool
                True/False based on whether the meta variable was set.
            """
            success = False

            updated_msg_vals = {}
            updated_msg_vals['channel'] = self.__config.channel
            updated_msg_vals['mv_meta_code'] = Msg.SetMetaVariable.Client.mv_channel_codes[mv_num]
            updated_msg_vals['mv_data'] = mv_value

            set_mv_msg_tx_bin = Msg.SetMetaVariable.Client.pack(updated_msg_vals)
            response_msg_bin = self._send_receive_msg(
                set_mv_msg_tx_bin)

            if response_msg_bin:
                set_mv_msg_rx_dict = Msg.SetMetaVariable.Server.unpack(
                    response_msg_bin)
                if set_mv_msg_rx_dict['result'] == 'success':
                    success = True
                    logger.info(
                        f'Successfully set meta variable {mv_num} to a value of {mv_value}')
                    logger.debug(set_mv_msg_rx_dict)
                else:
                    logger.error(
                        f'Failed to set meta variable {mv_num} to a value of {mv_value}! Issue: {set_mv_msg_rx_dict["result"]}')

            return success

  `def start_test(self) ‑> bool`

    Starts channel on method specified in config.

    ## Returns

    `success` :`bool`
      True/False based on whether the test was started without issue.
    Expand source code

        def start_test(self) -> bool:
            """
            Starts channel on method specified in config.

            Returns
            -------
            success : bool
                True/False based on whether the test was started without issue.
            """
            success = False

            if not self.__config.test_name:
                logger.error("Test name undefined!")
                return success

            # Make sure the schedule is assigned before starting the test to avoid any funny business
            if self.assign_schedule():
                start_test_msg_tx_bin = Msg.StartSchedule.Client.pack(
                    {'channel': self.__config.channel, 'test_name': self.__config.test_name})
                response_msg_bin = self._send_receive_msg(start_test_msg_tx_bin)

                if response_msg_bin:
                    start_test_msg_rx_dict = Msg.StartSchedule.Server.unpack(
                        response_msg_bin)
                    if start_test_msg_rx_dict['result'] == 'success':
                        success = True
                        logger.info(
                            f'Successfully started test {self.__config.test_name} with schedule {self.__config.schedule_name} on channel {self.__config.channel}')
                        logger.debug(start_test_msg_rx_dict)
                    else:
                        logger.error(
                            f'Failed to start test {self.__config.test_name} with schedule {self.__config.schedule_name} on channel {self.__config.channel}. Issue: {start_test_msg_rx_dict["result"]}')

            return success

  `def stop_test(self) ‑> bool`

    Stops the test running on the channel specified in the config.

    ## Returns

    `success` :`bool`
      True/False based on whether the test stopped without issue. Also returns True if no test was running on the channel.
    Expand source code

        def stop_test(self) -> bool:
            """
            Stops the test running on the channel specified in the config.

            Returns
            -------
            success : bool
                True/False based on whether the test stopped without issue.
                Also returns True if no test was running on the channel.
            """
            success = False

            stop_test_msg_tx_bin = Msg.StopSchedule.Client.pack(
                {'channel': self.__config.channel})
            response_msg_bin = self._send_receive_msg(
                stop_test_msg_tx_bin)

            if response_msg_bin:
                stop_test_msg_rx_dict = Msg.StopSchedule.Server.unpack(
                    response_msg_bin)
                if stop_test_msg_rx_dict['result'] == 'success':
                    success = True
                    logger.info(
                        f'Successfully stopped test on channel {self.__config.channel}')
                    logger.debug(stop_test_msg_rx_dict)
                else:
                    logger.error(
                        f'Failed to stop test on channel {self.__config.channel}! Issue: {stop_test_msg_rx_dict["result"]}')

            return success

  ### Inherited members

  - `CyclerInterface`:
    - `get_login_feedback`
    - `get_num_channels`
`class ChannelInterfaceConfig (**data: Any)`

  Holds channel config information for the CyclerInterface class.

  ## Parameters

      channel : int
          The channel to target with the ChannelInterface class instance.
      test_name : *optional*
          The test name to use if using the ChannelInterface to start a test.
      schedule_name : str
          The name of the schedule file to use if using the ChannelInterface to start a test.
      ip_address : str
          The IP address of the Arbin host computer.
      port : int
          The TCP port to communicate through.
      timeout_s : float
          How long to wait before timing out on TCP communication. Defaults to 3 seconds.
      msg_buffer_size : int
           How big of a message buffer to use for sending/receiving messages.
          A minimum of 1024 bytes is recommended. Defaults to 4096 bytes.

  Create a new model by parsing and validating input data from keyword arguments.

  Raises ValidationError if the input data cannot be parsed to form a valid model.

  Expand source code

      class ChannelInterfaceConfig(BaseModel):
          '''
          Holds channel config information for the CyclerInterface class.

          Parameters
          ----------
              channel : int
                  The channel to target with the ChannelInterface class instance.
              test_name : *optional*
                  The test name to use if using the ChannelInterface to start a test.
              schedule_name : str
                  The name of the schedule file to use if using the ChannelInterface to start a test.
              ip_address : str
                  The IP address of the Arbin host computer.
              port : int
                  The TCP port to communicate through.
              timeout_s : float
                  How long to wait before timing out on TCP communication. Defaults to 3 seconds.
              msg_buffer_size : int
                   How big of a message buffer to use for sending/receiving messages.
                  A minimum of 1024 bytes is recommended. Defaults to 4096 bytes.
          '''
          channel: int
          test_name: str = None
          schedule_name: str = None
          ip_address: str
          port: int
          timeout_s: float = 3.0
          msg_buffer_size: int = 4096

          @validator('channel')
          def username_alphanumeric(cls, v):
              if v < 1:
                  raise ValueError('Channel must be greater than zero!')
              return v-1

  ### Ancestors

  - pydantic.main.BaseModel
  - pydantic.utils.Representation

  ### Class variables

  `var channel : int`
  `var ip_address : str`
  `var msg_buffer_size : int`
  `var port : int`
  `var schedule_name : str`
  `var test_name : str`
  `var timeout_s : float`

  ### Static methods

  `def username_alphanumeric(v)`
    Expand source code

        @validator('channel')
        def username_alphanumeric(cls, v):
            if v < 1:
                raise ValueError('Channel must be greater than zero!')
            return v-1