dopes.equipment_control.mecom.mecom API documentation
Description: " The magic happens in this file.

# Module `dopes.equipment_control.mecom.mecom`

" The magic happens in this file.

## Classes

`class ACK`
  Expand source code

      class ACK(MeFrame):
          """
          ACK command sent by the device.
          """
          _SOURCE = "!"

          def decompose(self, frame_bytes):
              """
              Takes bytes as input and builds the instance.
              :param frame_bytes: bytes
              :return:
              """
              frame_bytes = self._SOURCE.encode() + frame_bytes
              self._decompose_header(frame_bytes)

              frame = frame_bytes.decode()
              self.CRC = int(frame[-4:], 16)

  ACK command sent by the device.

  ### Ancestors

  - MeFrame

  ### Methods

  `def decompose(self, frame_bytes)`
    Expand source code

        def decompose(self, frame_bytes):
            """
            Takes bytes as input and builds the instance.
            :param frame_bytes: bytes
            :return:
            """
            frame_bytes = self._SOURCE.encode() + frame_bytes
            self._decompose_header(frame_bytes)

            frame = frame_bytes.decode()
            self.CRC = int(frame[-4:], 16)

    Takes bytes as input and builds the instance. :param frame_bytes: bytes :return:

  ### Inherited members

  - `MeFrame`:
    - `CalcCRC_CCITT`
    - `compose`
    - `crc`
`class DeviceError`
  Expand source code

      class DeviceError(MeFrame):
          """
          Queries failing return a device error, implemented as repsonse by this class.
          """
          _SOURCE = "!"

          def __init__(self):
              """
              Read error codes from command.py and parse into a list of Error() instances.
              """
              super(DeviceError, self).__init__()
              self._ERRORS = []
              for error in ERRORS:
                  self._ERRORS.append(Error(error))

          def _get_by_code(self, code):
              """
              Returns a Error() identified by it's error code.
              :param code: int
              :return: Error()
              """
              for error in self._ERRORS:
                  if error.code == code:
                      return error
              # we do not need to raise here since error are well defined

          def compose(self, part=False):
              """
              Device errors have a different but simple structure.
              :param part: bool
              :return:
              """
              # first part
              frame = self._SOURCE + "{:02X}".format(self.ADDRESS) + "{:04X}".format(self.SEQUENCE)
              # payload is ['+', #_of_error]
              frame += self.PAYLOAD[0]
              frame += "{:02x}".format(self.PAYLOAD[1])
              # if we only want a partial frame, return here
              if part:
                  return frame.encode()
              # add checksum
              if self.CRC is None:
                  self.crc()
              frame += "{:04X}".format(self.CRC)
              # add end of line (carriage return)
              frame += self._EOL
              return frame.encode()

          def decompose(self, frame_bytes):
              """
              Again, different but consistent structure.
              :param frame_bytes: bytes
              :return:
              """
              frame_bytes = self._SOURCE.encode() + frame_bytes
              self._decompose_header(frame_bytes)
              frame = frame_bytes.decode()
              self.PAYLOAD.append(frame[7])
              self.PAYLOAD.append(int(frame[8:10], 16))
              self.crc(int(frame[-4:], 16))

          def error(self):
              """
              Returns error code, description and symbol as [str,].
              :return: [str, str, str]
              """
              error_code = self.PAYLOAD[1]
              # returns [code, description, symbol]
              return self._get_by_code(error_code).as_list()

  Queries failing return a device error, implemented as repsonse by this class.

  Read error codes from command.py and parse into a list of Error() instances.

  ### Ancestors

  - MeFrame

  ### Methods

  `def compose(self, part=False)`
    Expand source code

        def compose(self, part=False):
            """
            Device errors have a different but simple structure.
            :param part: bool
            :return:
            """
            # first part
            frame = self._SOURCE + "{:02X}".format(self.ADDRESS) + "{:04X}".format(self.SEQUENCE)
            # payload is ['+', #_of_error]
            frame += self.PAYLOAD[0]
            frame += "{:02x}".format(self.PAYLOAD[1])
            # if we only want a partial frame, return here
            if part:
                return frame.encode()
            # add checksum
            if self.CRC is None:
                self.crc()
            frame += "{:04X}".format(self.CRC)
            # add end of line (carriage return)
            frame += self._EOL
            return frame.encode()

    Device errors have a different but simple structure. :param part: bool :return:

  `def decompose(self, frame_bytes)`
    Expand source code

        def decompose(self, frame_bytes):
            """
            Again, different but consistent structure.
            :param frame_bytes: bytes
            :return:
            """
            frame_bytes = self._SOURCE.encode() + frame_bytes
            self._decompose_header(frame_bytes)
            frame = frame_bytes.decode()
            self.PAYLOAD.append(frame[7])
            self.PAYLOAD.append(int(frame[8:10], 16))
            self.crc(int(frame[-4:], 16))

    Again, different but consistent structure. :param frame_bytes: bytes :return:

  `def error(self)`
    Expand source code

        def error(self):
            """
            Returns error code, description and symbol as [str,].
            :return: [str, str, str]
            """
            error_code = self.PAYLOAD[1]
            # returns [code, description, symbol]
            return self._get_by_code(error_code).as_list()

    Returns error code, description and symbol as [str,]. :return: [str, str, str]

  ### Inherited members

  - `MeFrame`:
    - `CalcCRC_CCITT`
    - `crc`
`class Error (error_dict)`
  Expand source code

      class Error(object):
          """"
          Every error dict from commands.py is parsed into a Error instance.
          """

          def __init__(self, error_dict):
              """
              Takes a dict e.g. {"code": 1, "symbol": "EER_CMD_NOT_AVAILABLE", "description": "Command not available"} which
              defines a error specified by the protocol.
              :param error_dict: dict
              """
              self.code = error_dict["code"]
              self.symbol = error_dict["symbol"]
              self.description = error_dict["description"]

          def as_list(self):
              """
              Returns a list representation of this object.
              :return: list
              """
              return [self.code, self.description, self.symbol]

  " Every error dict from commands.py is parsed into a Error instance.

  Takes a dict e.g. {"code": 1, "symbol": "EER_CMD_NOT_AVAILABLE", "description": "Command not available"} which defines a error specified by the protocol. :param error_dict: dict

  ### Methods

  `def as_list(self)`
    Expand source code

        def as_list(self):
            """
            Returns a list representation of this object.
            :return: list
            """
            return [self.code, self.description, self.symbol]

    Returns a list representation of this object. :return: list

`class IF (address=0, parameter_instance=1)`
  Expand source code

      class IF(Query):
          """
          Implementing device info query.
          """
          _PAYLOAD_START = '?IF'

          def __init__(self, address=0, parameter_instance=1):
              """
              Create a query to set a parameter value.
              :param address: int
              :param parameter_instance: int
              """

              # init header (equal for get and set queries)
              super(IF, self).__init__(parameter=None,
                               address=address,
                               parameter_instance=parameter_instance)

              # no need to initialize response format, we want ACK

  Implementing device info query.

  Create a query to set a parameter value. :param address: int :param parameter_instance: int

  ### Ancestors

  - Query
  - MeFrame

  ### Inherited members

  - `Query`:
    - `CalcCRC_CCITT`
    - `compose`
    - `crc`
    - `set_response`
`class IFResponse`
  Expand source code

      class IFResponse(MeFrame):
          """
          ACK command sent by the device.
          """
          _SOURCE = "!"

          def crc(self, in_crc=None):
              """
              ACK has the same checksum as the VS command.
              :param in_crc: int
              :return:
              """
              pass

          def decompose(self, frame_bytes):
              """
              Takes bytes as input and builds the instance.
              :param frame_bytes: bytes
              :return:
              """
              frame_bytes = self._SOURCE.encode() + frame_bytes
              self._decompose_header(frame_bytes)

              frame = frame_bytes.decode()
              self.PAYLOAD = frame[7:-4]
              self.CRC = int(frame[-4:], 16)

  ACK command sent by the device.

  ### Ancestors

  - MeFrame

  ### Methods

  `def crc(self, in_crc=None)`
    Expand source code

        def crc(self, in_crc=None):
            """
            ACK has the same checksum as the VS command.
            :param in_crc: int
            :return:
            """
            pass

    ACK has the same checksum as the VS command. :param in_crc: int :return:

  `def decompose(self, frame_bytes)`
    Expand source code

        def decompose(self, frame_bytes):
            """
            Takes bytes as input and builds the instance.
            :param frame_bytes: bytes
            :return:
            """
            frame_bytes = self._SOURCE.encode() + frame_bytes
            self._decompose_header(frame_bytes)

            frame = frame_bytes.decode()
            self.PAYLOAD = frame[7:-4]
            self.CRC = int(frame[-4:], 16)

    Takes bytes as input and builds the instance. :param frame_bytes: bytes :return:

  ### Inherited members

  - `MeFrame`:
    - `CalcCRC_CCITT`
    - `compose`
`class MeCom (serialport='/dev/ttyUSB0', timeout=1, baudrate=57600, metype='TEC')`
  Expand source code

      class MeCom(MeComSerial):
          """
          Deprecated. Use MeComSerial instead.
          """
          pass

  Deprecated. Use MeComSerial instead.

  Initialize communication with serial port. :param serialport: str: Linux example: '/dev/ttyUSB0', Windows example: 'COM1' :param timeout: int :param metype: str: either 'TEC', 'LDD-112x', 'LDD-130x' or 'LDD-1321'

  ### Ancestors

  - MeComSerial
  - MeComCommon

  ### Inherited members

  - `MeComSerial`:
    - `get_parameter`
    - `get_parameter_raw`
    - `info`
    - `reset_device`
    - `set_parameter`
    - `set_parameter_raw`
    - `status`
    - `trigger_save_to_flash`
    - `write_to_flash`
`class MeComCommon (metype='TEC')`
  Expand source code

      class MeComCommon:
          """
          Shared communication class
          """
          SEQUENCE_COUNTER = 1

          def __init__(self, metype='TEC'):
              """
              Initialize communication with serial port.
              :param serialport: str
              :param timeout: int
              :param metype: str: either 'TEC', 'LDD-112x', 'LDD-130x' or 'LDD-1321'
              """
              self.lock = Lock()

              # initialize parameters
              self.PARAMETERS = ParameterList(metype)

          def _find_parameter(self, parameter_name, parameter_id):
              """
              Return Parameter() with either name or id given.
              :param parameter_name: str
              :param parameter_id: int
              :return: Parameter
              """
              assert parameter_name is not None or parameter_id is not None

              return self.PARAMETERS.get_by_name(parameter_name) if parameter_name is not None\
                  else self.PARAMETERS.get_by_id(parameter_id)

          def _inc(self):
              self.SEQUENCE_COUNTER += 1
              # sequence in controller is int16 and overflows
              self.SEQUENCE_COUNTER = self.SEQUENCE_COUNTER % (2**16)

          @staticmethod
          def _raise(query):
              """
              If DeviceError is received, raise!
              :param query: VR or VS
              :return:
              """
              # did we encounter an error?
              if type(query.RESPONSE) is DeviceError:
                  code, description, symbol = query.RESPONSE.error()
                  raise ResponseException("device {} raised {}".format(query.RESPONSE.ADDRESS, description))

          def _get(self, parameter_name=None, parameter_id=None, *args, **kwargs):
              """
              Get a query object for a VR command.
              :param parameter_name:
              :param parameter_id:
              :param args:
              :param kwargs:
              :return:
              """

              # search in DataFrame returns a dict
              parameter = self._find_parameter(parameter_name, parameter_id)

              # execute query
              vr = self._execute(VR(parameter=parameter, *args, **kwargs))

              # print(vr.PAYLOAD)
              # print(vr.RESPONSE.PAYLOAD)
              # return the query with response
              return vr

          def _get_raw(self, parameter_id, parameter_format, *args, **kwargs):
              """
              Get a query object for a VR command (raw version).
              :param parameter:
              :param args:
              :param kwargs:
              :return:
              """

              # construct from raw id and format specifier
              parameter = Parameter({"id": parameter_id, "name": None, "format": parameter_format})

              # execute query
              vr = self._execute(VR(parameter=parameter, *args, **kwargs))

              # print(vr.PAYLOAD)
              # print(vr.RESPONSE.PAYLOAD)
              # return the query with response
              return vr

          def _set(self, value, parameter_name=None, parameter_id=None, *args, **kwargs):
              """
              Get a query object for a VS command.
              :param value:
              :param parameter_name:
              :param parameter_id:
              :param args:
              :param kwargs:
              :return:
              """

              # search in DataFrame returns a dict
              parameter = self._find_parameter(parameter_name, parameter_id)

              # execute query
              vs = self._execute(VS(value=value, parameter=parameter, *args, **kwargs))

              # return the query with response
              return vs

          def _set_raw(self, value, parameter_id, parameter_format, *args, **kwargs):
              """
              Get a query object for a VS command (raw version).
              :param value:
              :param parameter:
              :param args:
              :param kwargs:
              :return:
              """

              # construct from raw id and format specifier
              parameter = Parameter({"id": parameter_id, "name": None, "format": parameter_format})

              # execute query
              vs = self._execute(VS(value=value, parameter=parameter, *args, **kwargs))

              # return the query with response
              return vs

          def get_parameter(self, parameter_name=None, parameter_id=None, *args, **kwargs):
              """
              Get the value of a parameter given by name or id.
              Returns a list of success and value.
              :param parameter_name:
              :param parameter_id:
              :param args:
              :param kwargs:
              :return: int or float
              """
              # get the query object
              vr = self._get(parameter_id=parameter_id, parameter_name=parameter_name, *args, **kwargs)

              return vr.RESPONSE.PAYLOAD[0]

          def get_parameter_raw(self, parameter_id, parameter_format, *args, **kwargs):
              """
              Get the value of a parameter given by its id and format specifier.
              note: use get_parameter() if you only want to use known commands
              Returns a list of success and value.
              :param parameter:
              :param args:
              :param kwargs:
              :return: int or float
              """
              # get the query object
              vr = self._get_raw(parameter_id=parameter_id, parameter_format=parameter_format, *args, **kwargs)

              return vr.RESPONSE.PAYLOAD[0]

          def set_parameter(self, value, parameter_name=None, parameter_id=None, *args, **kwargs):
              """
              Set the new value of a parameter given by name or id.
              Returns success.
              :param value:
              :param parameter_name:
              :param parameter_id:
              :param args:
              :param kwargs:
              :return: bool
              """
              # get the query object
              vs = self._set(value=value, parameter_id=parameter_id, parameter_name=parameter_name, *args, **kwargs)

              # check if value setting has succeeded
              #
              # Not necessary as we get an acknowledge response or Value is out of range
              # exception when an invalid value was passed.
              # current implementation also often fails due to rounding, e.g. setting 1.0
              # but returning 0.999755859375 when performing a self.get_parameter
              # value_set = self.get_parameter(parameter_id=parameter_id, parameter_name=parameter_name, *args, **kwargs)

              # return True if we got an ACK
              return type(vs.RESPONSE) == ACK

          def set_parameter_raw(self, value, parameter_id, parameter_format, *args, **kwargs):
              """
              Set the new value of a parameter given by its id and format specifier.
              note: use set_parameter() if you only want to use known commands
              Returns success.
              :param value:
              :param parameter:
              :param args:
              :param kwargs:
              :return: bool
              """
              # get the query object
              vs = self._set_raw(value=value, parameter_id=parameter_id, parameter_format=parameter_format, *args, **kwargs)

              # check if value setting has succeeded
              #
              # Not necessary as we get an acknowledge response or Value is out of range
              # exception when an invalid value was passed.
              # current implementation also often fails due to rounding, e.g. setting 1.0
              # but returning 0.999755859375 when performing a self.get_parameter
              # value_set = self.get_parameter(parameter_id=parameter_id, parameter_name=parameter_name, *args, **kwargs)

              # return True if we got an ACK
              return type(vs.RESPONSE) == ACK

          def reset_device(self,*args, **kwargs):
              """
              Resets the device after an error has occured
              """
              rs = self._execute(RS(*args, **kwargs))
              return type(rs.RESPONSE) == ACK

          def info(self,*args, **kwargs):
              """
              Resets the device after an error has occured
              """
              info = self._execute(IF(*args, **kwargs))
              return info.RESPONSE.PAYLOAD

          # returns device address
          identify = partialmethod(get_parameter, parameter_name="Device Address")
          """
          Returns success and device address as int.
          """

          def status(self, *args, **kwargs):
              """
              Get the device status.
              Returns success and status as readable str.
              :param args:
              :param kwargs:
              :return: [bool, str]
              """
              # query device status
              status_id = self.get_parameter(parameter_name="Device Status", *args, **kwargs)

              if status_id == 0:
                  status_name = "Init"
              elif status_id == 1:
                  status_name = "Ready"
              elif status_id == 2:
                  status_name = "Run"
              elif status_id == 3:
                  status_name = "Error"
              elif status_id == 4:
                  status_name = "Bootloader"
              elif status_id == 5:
                  status_name = "Device will Reset within next 200ms"
              else:
                  status_name = "Unknown"

              # return address and status
              return status_name

          # enable or disable auto saving to flash
          enable_autosave = partialmethod(set_parameter, value=0, parameter_name="Save Data to Flash")
          disable_autosave = partialmethod(set_parameter, value=1, parameter_name="Save Data to Flash")

          def write_to_flash(self, *args, **kwargs):
              """
              Write parameters to flash.
              Note: This function only works on:
               - TEC Controllers using a firmware < v6.00
               - LDD-130x devices with a firmware < v2.00
               - LDD-112x devices on any firmware
              for devices not listed here, refer to the device documentation
              and check whether the old automatic flash saving mechanism
              is used on your device
              :param args:
              :param kwargs:
              :return: bool
              """
              self.enable_autosave()
              timer_start = time.time()

              # value 0 means "All Parameters are saved to Flash"
              while self.get_parameter(parameter_name="Flash Status") != 0:
                  # check for timeout
                  if time.time() - timer_start > 10:
                      raise ResponseTimeout("writing to flash timed out!")
                  time.sleep(0.5)

              self.disable_autosave()

              return True

          def trigger_save_to_flash(self, *args, **kwargs):
              """
              Writes all parameter values to the flash of the device.
              Note: This function only works on:
               - TEC Controllers using a firmware >= v6.00
               - LDD-130x devices with a firmware >= v2.00
               - LDD-1321 devices on any firmware
              for devices not listed here, refer to the device documentation
              and check whether the new explicit flash saving mechanism
              is used on your device
              """
              rs = self._execute(SP(*args, **kwargs))
              return type(rs.RESPONSE) == ACK

  Shared communication class

  Initialize communication with serial port. :param serialport: str :param timeout: int :param metype: str: either 'TEC', 'LDD-112x', 'LDD-130x' or 'LDD-1321'

  ### Subclasses

  - MeComSerial
  - MeComTcp

  ### Class variables

  `var SEQUENCE_COUNTER`

  ### Methods

  `def disable_autosave(self, *, value=1, parameter_name='Save Data to Flash', parameter_id=None, **kwargs)`
    Expand source code

        def _method(cls_or_self, /, *args, **keywords):
            keywords = {**self.keywords, **keywords}
            return self.func(cls_or_self, *self.args, *args, **keywords)

  `def enable_autosave(self, *, value=0, parameter_name='Save Data to Flash', parameter_id=None, **kwargs)`
    Expand source code

        def _method(cls_or_self, /, *args, **keywords):
            keywords = {**self.keywords, **keywords}
            return self.func(cls_or_self, *self.args, *args, **keywords)

  `def get_parameter(self, parameter_name=None, parameter_id=None, *args, **kwargs)`
    Expand source code

        def get_parameter(self, parameter_name=None, parameter_id=None, *args, **kwargs):
            """
            Get the value of a parameter given by name or id.
            Returns a list of success and value.
            :param parameter_name:
            :param parameter_id:
            :param args:
            :param kwargs:
            :return: int or float
            """
            # get the query object
            vr = self._get(parameter_id=parameter_id, parameter_name=parameter_name, *args, **kwargs)

            return vr.RESPONSE.PAYLOAD[0]

    Get the value of a parameter given by name or id. Returns a list of success and value. :param parameter_name: :param parameter_id: :param args: :param kwargs: :return: int or float

  `def get_parameter_raw(self, parameter_id, parameter_format, *args, **kwargs)`
    Expand source code

        def get_parameter_raw(self, parameter_id, parameter_format, *args, **kwargs):
            """
            Get the value of a parameter given by its id and format specifier.
            note: use get_parameter() if you only want to use known commands
            Returns a list of success and value.
            :param parameter:
            :param args:
            :param kwargs:
            :return: int or float
            """
            # get the query object
            vr = self._get_raw(parameter_id=parameter_id, parameter_format=parameter_format, *args, **kwargs)

            return vr.RESPONSE.PAYLOAD[0]

    Get the value of a parameter given by its id and format specifier. note: use get_parameter() if you only want to use known commands Returns a list of success and value. :param parameter: :param args: :param kwargs: :return: int or float

  `def identify(self, *, parameter_name='Device Address', parameter_id=None, **kwargs)`
    Expand source code

        def _method(cls_or_self, /, *args, **keywords):
            keywords = {**self.keywords, **keywords}
            return self.func(cls_or_self, *self.args, *args, **keywords)

  `def info(self, *args, **kwargs)`
    Expand source code

        def info(self,*args, **kwargs):
            """
            Resets the device after an error has occured
            """
            info = self._execute(IF(*args, **kwargs))
            return info.RESPONSE.PAYLOAD

    Resets the device after an error has occured

  `def reset_device(self, *args, **kwargs)`
    Expand source code

        def reset_device(self,*args, **kwargs):
            """
            Resets the device after an error has occured
            """
            rs = self._execute(RS(*args, **kwargs))
            return type(rs.RESPONSE) == ACK

    Resets the device after an error has occured

  `def set_parameter(self, value, parameter_name=None, parameter_id=None, *args, **kwargs)`
    Expand source code

        def set_parameter(self, value, parameter_name=None, parameter_id=None, *args, **kwargs):
            """
            Set the new value of a parameter given by name or id.
            Returns success.
            :param value:
            :param parameter_name:
            :param parameter_id:
            :param args:
            :param kwargs:
            :return: bool
            """
            # get the query object
            vs = self._set(value=value, parameter_id=parameter_id, parameter_name=parameter_name, *args, **kwargs)

            # check if value setting has succeeded
            #
            # Not necessary as we get an acknowledge response or Value is out of range
            # exception when an invalid value was passed.
            # current implementation also often fails due to rounding, e.g. setting 1.0
            # but returning 0.999755859375 when performing a self.get_parameter
            # value_set = self.get_parameter(parameter_id=parameter_id, parameter_name=parameter_name, *args, **kwargs)

            # return True if we got an ACK
            return type(vs.RESPONSE) == ACK

    Set the new value of a parameter given by name or id. Returns success. :param value: :param parameter_name: :param parameter_id: :param args: :param kwargs: :return: bool

  `def set_parameter_raw(self, value, parameter_id, parameter_format, *args, **kwargs)`
    Expand source code

        def set_parameter_raw(self, value, parameter_id, parameter_format, *args, **kwargs):
            """
            Set the new value of a parameter given by its id and format specifier.
            note: use set_parameter() if you only want to use known commands
            Returns success.
            :param value:
            :param parameter:
            :param args:
            :param kwargs:
            :return: bool
            """
            # get the query object
            vs = self._set_raw(value=value, parameter_id=parameter_id, parameter_format=parameter_format, *args, **kwargs)

            # check if value setting has succeeded
            #
            # Not necessary as we get an acknowledge response or Value is out of range
            # exception when an invalid value was passed.
            # current implementation also often fails due to rounding, e.g. setting 1.0
            # but returning 0.999755859375 when performing a self.get_parameter
            # value_set = self.get_parameter(parameter_id=parameter_id, parameter_name=parameter_name, *args, **kwargs)

            # return True if we got an ACK
            return type(vs.RESPONSE) == ACK

    Set the new value of a parameter given by its id and format specifier. note: use set_parameter() if you only want to use known commands Returns success. :param value: :param parameter: :param args: :param kwargs: :return: bool

  `def status(self, *args, **kwargs)`
    Expand source code

        def status(self, *args, **kwargs):
            """
            Get the device status.
            Returns success and status as readable str.
            :param args:
            :param kwargs:
            :return: [bool, str]
            """
            # query device status
            status_id = self.get_parameter(parameter_name="Device Status", *args, **kwargs)

            if status_id == 0:
                status_name = "Init"
            elif status_id == 1:
                status_name = "Ready"
            elif status_id == 2:
                status_name = "Run"
            elif status_id == 3:
                status_name = "Error"
            elif status_id == 4:
                status_name = "Bootloader"
            elif status_id == 5:
                status_name = "Device will Reset within next 200ms"
            else:
                status_name = "Unknown"

            # return address and status
            return status_name

    Get the device status. Returns success and status as readable str. :param args: :param kwargs: :return: [bool, str]

  `def trigger_save_to_flash(self, *args, **kwargs)`
    Expand source code

        def trigger_save_to_flash(self, *args, **kwargs):
            """
            Writes all parameter values to the flash of the device.
            Note: This function only works on:
             - TEC Controllers using a firmware >= v6.00
             - LDD-130x devices with a firmware >= v2.00
             - LDD-1321 devices on any firmware
            for devices not listed here, refer to the device documentation
            and check whether the new explicit flash saving mechanism
            is used on your device
            """
            rs = self._execute(SP(*args, **kwargs))
            return type(rs.RESPONSE) == ACK

    Writes all parameter values to the flash of the device. Note: This function only works on: - TEC Controllers using a firmware >= v6.00 - LDD-130x devices with a firmware >= v2.00 - LDD-1321 devices on any firmware for devices not listed here, refer to the device documentation and check whether the new explicit flash saving mechanism is used on your device

  `def write_to_flash(self, *args, **kwargs)`
    Expand source code

        def write_to_flash(self, *args, **kwargs):
            """
            Write parameters to flash.
            Note: This function only works on:
             - TEC Controllers using a firmware < v6.00
             - LDD-130x devices with a firmware < v2.00
             - LDD-112x devices on any firmware
            for devices not listed here, refer to the device documentation
            and check whether the old automatic flash saving mechanism
            is used on your device
            :param args:
            :param kwargs:
            :return: bool
            """
            self.enable_autosave()
            timer_start = time.time()

            # value 0 means "All Parameters are saved to Flash"
            while self.get_parameter(parameter_name="Flash Status") != 0:
                # check for timeout
                if time.time() - timer_start > 10:
                    raise ResponseTimeout("writing to flash timed out!")
                time.sleep(0.5)

            self.disable_autosave()

            return True

    Write parameters to flash. Note: This function only works on: - TEC Controllers using a firmware < v6.00 - LDD-130x devices with a firmware < v2.00 - LDD-112x devices on any firmware for devices not listed here, refer to the device documentation and check whether the old automatic flash saving mechanism is used on your device :param args: :param kwargs: :return: bool

`class MeComSerial (serialport='/dev/ttyUSB0', timeout=1, baudrate=57600, metype='TEC')`
  Expand source code

      class MeComSerial(MeComCommon):
          """
          Main class (Serial). Import this one:
          from qao.devices.mecom import MeComSerial

          For a usage example see __main__
          """
          SEQUENCE_COUNTER = 1

          def __init__(self, serialport="/dev/ttyUSB0", timeout=1, baudrate=57600, metype='TEC'):
              """
              Initialize communication with serial port.
              :param serialport: str: Linux example: '/dev/ttyUSB0', Windows example: 'COM1'
              :param timeout: int
              :param metype: str: either 'TEC', 'LDD-112x', 'LDD-130x' or 'LDD-1321'
              """
              # initialize serial connection
              self.ser = Serial(port=serialport, timeout=timeout, write_timeout=timeout, baudrate=baudrate)

              # start protocol thread
              # self.protocol = ReaderThread(serial_instance=self.ser, protocol_factory=MePacket)
              # self.receiver = self.protocol.__enter__()

              # initialize parameters
              self.PARAMETERS = ParameterList(metype)

              super().__init__(metype)

          def __exit__(self, exc_type, exc_val, exc_tb):
              self.ser.__exit__(exc_type, exc_val, exc_tb)

          def __enter__(self):
              return self

          def stop(self):
              self.ser.flush()
              self.ser.close()

          def _read(self, size):
              """
              Read n=size bytes from serial, if <n bytes are received (serial.read() return because of timeout), raise a timeout.
              """
              recv = self.ser.read(size=size)
              if len(recv) < size:
                  raise ResponseTimeout("timeout while communication via serial")
              else:
                  return recv

          def _execute(self, query):
              self.lock.acquire()

              try:
                  # clear buffers
                  self.ser.reset_output_buffer()
                  self.ser.reset_input_buffer()

                  query.set_sequence(self.SEQUENCE_COUNTER)
                  # send query
                  self.ser.write(query.compose())
                  # print(query.compose())

                  # flush write cache
                  self.ser.flush()

                  # initialize response and carriage return
                  cr = "\r".encode()
                  response_frame = b''
                  response_byte = self._read(size=1)  # read one byte at a time, timeout is set on instance level

                  # read until stop byte
                  while response_byte != cr:
                      response_frame += response_byte
                      response_byte = self._read(size=1)
              finally:
                  # increment sequence counter
                  self._inc()
                  self.lock.release()

              # strip source byte (! or #, but for a response always !)
              response_frame = response_frame[1:]

              # print(response_frame)
              query.set_response(response_frame)

              # did we encounter an error?
              self._raise(query)

              return query

  Main class (Serial). Import this one: from qao.devices.mecom import MeComSerial

  For a usage example see main

  Initialize communication with serial port. :param serialport: str: Linux example: '/dev/ttyUSB0', Windows example: 'COM1' :param timeout: int :param metype: str: either 'TEC', 'LDD-112x', 'LDD-130x' or 'LDD-1321'

  ### Ancestors

  - MeComCommon

  ### Subclasses

  - MeCom

  ### Class variables

  `var SEQUENCE_COUNTER`

  ### Methods

  `def stop(self)`
    Expand source code

        def stop(self):
            self.ser.flush()
            self.ser.close()

  ### Inherited members

  - `MeComCommon`:
    - `get_parameter`
    - `get_parameter_raw`
    - `info`
    - `reset_device`
    - `set_parameter`
    - `set_parameter_raw`
    - `status`
    - `trigger_save_to_flash`
    - `write_to_flash`
`class MeComTcp (ipaddress, ipport=50000, metype='TEC')`
  Expand source code

      class MeComTcp(MeComCommon):
          """
          Main class (TCP). Import this one:
          from qao.devices.mecom import MeComTCP

          For a usage example see __main__
          """
          SEQUENCE_COUNTER = 1

          def __init__(self, ipaddress, ipport=50000, metype='TEC'):
              """
              Initialize communication with TCP connection.
              :param ipaddress: str
              :param ipport: int
              :param timeout: int
              :param metype: str: either 'TEC', 'LDD-112x', 'LDD-130x' or 'LDD-1321'
              """
              # initialize network connection
              self.tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
              self.tcp.connect((ipaddress, ipport))

              # initialize parameters
              self.PARAMETERS = ParameterList(metype)

              super().__init__(metype)

          def __exit__(self, exc_type, exc_val, exc_tb):
              self.tcp.__exit__(exc_type, exc_val, exc_tb)

          def __enter__(self):
              return self

          def stop(self):
              self.tcp.close()

          def _read(self, size):
              """
              Read n=size bytes from TCP, if <n bytes are received, raise a timeout.
              """
              recv = b""
              while (size - len(recv)) > 0:
                  recv += self.tcp.recv(size - len(recv))
              if len(recv) < size:
                  raise ResponseTimeout("timeout while communication via network")
              else:
                  return recv

          def _execute(self, query):
              self.lock.acquire()

              try:
                  query.set_sequence(self.SEQUENCE_COUNTER)
                  # send query
                  self.tcp.sendall(query.compose())
                  # print(query.compose())

                  # initialize response and carriage return
                  cr = "\r".encode()
                  response_frame = b''
                  response_byte = self._read(size=1)  # read one byte at a time, timeout is set on instance level

                  # read until stop byte
                  while response_byte != cr:
                      response_frame += response_byte
                      response_byte = self._read(size=1)
              finally:
                  # increment sequence counter
                  self._inc()
                  self.lock.release()

              # strip source byte (! or #, but for a response always !)
              response_frame = response_frame[1:]

              # print(response_frame)
              query.set_response(response_frame)

              # did we encounter an error?
              self._raise(query)

              return query

  Main class (TCP). Import this one: from qao.devices.mecom import MeComTCP

  For a usage example see main

  Initialize communication with TCP connection. :param ipaddress: str :param ipport: int :param timeout: int :param metype: str: either 'TEC', 'LDD-112x', 'LDD-130x' or 'LDD-1321'

  ### Ancestors

  - MeComCommon

  ### Class variables

  `var SEQUENCE_COUNTER`

  ### Methods

  `def stop(self)`
    Expand source code

        def stop(self):
            self.tcp.close()

  ### Inherited members

  - `MeComCommon`:
    - `get_parameter`
    - `get_parameter_raw`
    - `info`
    - `reset_device`
    - `set_parameter`
    - `set_parameter_raw`
    - `status`
    - `trigger_save_to_flash`
    - `write_to_flash`
`class MeFrame`
  Expand source code

      class MeFrame(object):
          """
          Basis structure of a MeCom frame as defined in the specs.
          """
          _TYPES = {"UINT8": "!H", "UINT16": "!L", "INT32": "!i", "FLOAT32": "!f"}
          _SOURCE = ""
          _EOL = "\r"  # carriage return

          def __init__(self):
              self.ADDRESS = 0
              self.SEQUENCE = 0
              self.PAYLOAD = []
              self.CRC = None

          def CalcCRC_CCITT(self, input_data):
              """
              Calculates the CRC-CCITT checksum of the given data
              """
              CRC = 0

              for byte in input_data:
                  CRC ^= byte << 8
                  for _ in range(8):
                      if (CRC & 0x8000) != 0:
                          CRC = (CRC << 1) ^ 0x1021 # CCITT CRC-16 Polynomial
                      else:
                          CRC = CRC << 1
                      CRC &= 0xFFFF

              return CRC

          def crc(self, in_crc=None):
              """
              Calculates the checksum of a given frame, if a checksum is given as parameter, the two are compared.
              :param in_crc:
              :return: int
              """
              if self.CRC is None:
                  self.CRC = self.CalcCRC_CCITT(input_data=self.compose(part=True))

              # crc check
              # print(self.CRC)
              # print(in_crc)
              if in_crc is not None and in_crc != self.CRC:
                  raise WrongChecksum

          def set_sequence(self, sequence):
              self.SEQUENCE = sequence

          def compose(self, part=False):
              """
              Returns the frame as bytes, the return-value can be directly send via serial.
              :param part: bool
              :return: bytes
              """
              # first part
              frame = self._SOURCE + "{:02X}".format(self.ADDRESS) + "{:04X}".format(self.SEQUENCE)
              # payload can be str or float or int
              for p in self.PAYLOAD:
                  if type(p) is str:
                      frame += p
                  elif type(p) is int:
                      frame += "{:08X}".format(p)
                  elif type(p) is float:
                      # frame += hex(unpack('<I', pack('<f', p))[0])[2:].upper()  # please do not ask
                      # if p = 0 CRC fails, e.g. !01000400000000 composes to b'!0100040' / missing zero padding
                      frame += '{:08X}'.format(unpack('<I', pack('<f', p))[0])   #still do not aks
              # if we only want a partial frame, return here
              if part:
                  return frame.encode()
              # add checksum
              if self.CRC is None:
                  self.crc()
              frame += "{:04X}".format(self.CRC)
              # add end of line (carriage return)
              frame += self._EOL
              return frame.encode()

          def _decompose_header(self, frame_bytes):
              """
              Takes bytes as input and decomposes into the instance variables.
              :param frame_bytes: bytes
              :return:
              """
              frame = frame_bytes.decode()

              self._SOURCE = frame[0]
              self.ADDRESS = int(frame[1:3], 16)
              self.SEQUENCE = int(frame[3:7], 16)

  Basis structure of a MeCom frame as defined in the specs.

  ### Subclasses

  - ACK
  - DeviceError
  - IFResponse
  - Query
  - VRResponse

  ### Methods

  `def CalcCRC_CCITT(self, input_data)`
    Expand source code

        def CalcCRC_CCITT(self, input_data):
            """
            Calculates the CRC-CCITT checksum of the given data
            """
            CRC = 0

            for byte in input_data:
                CRC ^= byte << 8
                for _ in range(8):
                    if (CRC & 0x8000) != 0:
                        CRC = (CRC << 1) ^ 0x1021 # CCITT CRC-16 Polynomial
                    else:
                        CRC = CRC << 1
                    CRC &= 0xFFFF

            return CRC

    Calculates the CRC-CCITT checksum of the given data

  `def compose(self, part=False)`
    Expand source code

        def compose(self, part=False):
            """
            Returns the frame as bytes, the return-value can be directly send via serial.
            :param part: bool
            :return: bytes
            """
            # first part
            frame = self._SOURCE + "{:02X}".format(self.ADDRESS) + "{:04X}".format(self.SEQUENCE)
            # payload can be str or float or int
            for p in self.PAYLOAD:
                if type(p) is str:
                    frame += p
                elif type(p) is int:
                    frame += "{:08X}".format(p)
                elif type(p) is float:
                    # frame += hex(unpack('<I', pack('<f', p))[0])[2:].upper()  # please do not ask
                    # if p = 0 CRC fails, e.g. !01000400000000 composes to b'!0100040' / missing zero padding
                    frame += '{:08X}'.format(unpack('<I', pack('<f', p))[0])   #still do not aks
            # if we only want a partial frame, return here
            if part:
                return frame.encode()
            # add checksum
            if self.CRC is None:
                self.crc()
            frame += "{:04X}".format(self.CRC)
            # add end of line (carriage return)
            frame += self._EOL
            return frame.encode()

    Returns the frame as bytes, the return-value can be directly send via serial. :param part: bool :return: bytes

  `def crc(self, in_crc=None)`
    Expand source code

        def crc(self, in_crc=None):
            """
            Calculates the checksum of a given frame, if a checksum is given as parameter, the two are compared.
            :param in_crc:
            :return: int
            """
            if self.CRC is None:
                self.CRC = self.CalcCRC_CCITT(input_data=self.compose(part=True))

            # crc check
            # print(self.CRC)
            # print(in_crc)
            if in_crc is not None and in_crc != self.CRC:
                raise WrongChecksum

    Calculates the checksum of a given frame, if a checksum is given as parameter, the two are compared. :param in_crc: :return: int

  `def set_sequence(self, sequence)`
    Expand source code

        def set_sequence(self, sequence):
            self.SEQUENCE = sequence

`class Parameter (parameter_dict)`
  Expand source code

      class Parameter(object):
          """"
          Every parameter dict from commands.py is parsed into a Parameter instance.
          """

          def __init__(self, parameter_dict):
              """
              Takes a dict e.g. {"id": 104, "name": "Device Status", "format": "INT32"} and creates an object which can be
              passed to a Query().
              :param parameter_dict: dict
              """
              self.id = parameter_dict["id"]
              self.name = parameter_dict["name"]
              self.format = parameter_dict["format"]

  " Every parameter dict from commands.py is parsed into a Parameter instance.

  Takes a dict e.g. {"id": 104, "name": "Device Status", "format": "INT32"} and creates an object which can be passed to a Query(). :param parameter_dict: dict

`class ParameterList (metype='TEC')`
  Expand source code

      class ParameterList(object):
          """
          Contains a list of Parameter() for either TEC controller (metype = 'TEC'),
          LDD-112x (metype = 'LDD-112x'), LDD-130x (metype = 'LDD-130x') or LDD-1321 (metype = 'LDD-1321').
          Provides searching via id or name.
          The deprecated metype = 'LDD' is equal to passing metype = 'LDD-112x'.
          :param error_dict: dict
          """

          def __init__(self,metype='TEC'):
              """
              Reads the parameter dicts from commands.py.
              """
              self._PARAMETERS = []
              if metype == 'TEC':
                  for parameter in TEC_PARAMETERS:
                      self._PARAMETERS.append(Parameter(parameter))
              elif metype =='LDD-112x' or metype =='LDD':
                  for parameter in LDD_112x_PARAMETERS:
                      self._PARAMETERS.append(Parameter(parameter))
              elif metype =='LDD-130x':
                  for parameter in LDD_130x_PARAMETERS:
                      self._PARAMETERS.append(Parameter(parameter))
              elif metype =='LDD-1321':
                  for parameter in LDD_1321_PARAMETERS:
                      self._PARAMETERS.append(Parameter(parameter))
              else:
                  raise UnknownMeComType

          def get_by_id(self, id):
              """
              Returns a Parameter() identified by it's id.
              :param id: int
              :return: Parameter()
              """
              for parameter in self._PARAMETERS:
                  if parameter.id == id:
                      return parameter
              raise UnknownParameter

          def get_by_name(self, name):
              """
              Returns a Parameter() identified by it's name.
              :param name: str
              :return: Parameter()
              """
              for parameter in self._PARAMETERS:
                  if parameter.name == name:
                      return parameter
              raise UnknownParameter

  Contains a list of Parameter() for either TEC controller (metype = 'TEC'), LDD-112x (metype = 'LDD-112x'), LDD-130x (metype = 'LDD-130x') or LDD-1321 (metype = 'LDD-1321'). Provides searching via id or name. The deprecated metype = 'LDD' is equal to passing metype = 'LDD-112x'. :param error_dict: dict

  Reads the parameter dicts from commands.py.

  ### Methods

  `def get_by_id(self, id)`
    Expand source code

        def get_by_id(self, id):
            """
            Returns a Parameter() identified by it's id.
            :param id: int
            :return: Parameter()
            """
            for parameter in self._PARAMETERS:
                if parameter.id == id:
                    return parameter
            raise UnknownParameter

    Returns a Parameter() identified by it's id. :param id: int :return: Parameter()

  `def get_by_name(self, name)`
    Expand source code

        def get_by_name(self, name):
            """
            Returns a Parameter() identified by it's name.
            :param name: str
            :return: Parameter()
            """
            for parameter in self._PARAMETERS:
                if parameter.name == name:
                    return parameter
            raise UnknownParameter

    Returns a Parameter() identified by it's name. :param name: str :return: Parameter()

`class Query (parameter=None, address=0, parameter_instance=1)`
  Expand source code

      class Query(MeFrame):
          """
          Basic structure of a query to get or set a parameter. Has the attribute RESPONSE which contains the answer received
          by the device. The response is set via set_response
          """
          _SOURCE = "#"
          _PAYLOAD_START = None

          def __init__(self, parameter=None, address=0, parameter_instance=1):
              """
              To be initialized with a target device address (default=broadcast), the channel, teh sequence number and a
              Parameter() instance of the corresponding parameter.
              :param parameter: Parameter
              :param sequence: int
              :param address: int
              :param parameter_instance: int
              """
              super(Query, self).__init__()

              if hasattr(self, "_PAYLOAD_START"):
                  self.PAYLOAD.append(self._PAYLOAD_START)

              self.RESPONSE = None
              self._RESPONSE_FORMAT = None

              self.ADDRESS = address
              if parameter is not None:
                  # UNIT16 4 hex digits
                  self.PAYLOAD.append("{:04X}".format(parameter.id))
                  # UNIT8 2 hex digits
                  self.PAYLOAD.append("{:02X}".format(parameter_instance))

          def set_response(self, response_frame):
              """
              Takes the bytes received from the device as input and creates the corresponding response instance.
              :param response_frame: bytes
              :return:
              """
              # check the type of the response
              # is it an ACK packet?
              if len(response_frame) == 10:
                  self.RESPONSE = ACK()
                  self.RESPONSE.decompose(response_frame)
              # is it an info string packet/response_frame does not contain source (!)
              elif len(response_frame) == 30:
                  self.RESPONSE = IFResponse()
                  self.RESPONSE.decompose(response_frame)
              # is it an error packet?
              elif b'+' in response_frame:
                  self.RESPONSE = DeviceError()
                  self.RESPONSE.decompose(response_frame)
              # nope it's a response to a parameter query
              else:
                  self.RESPONSE = VRResponse(self._RESPONSE_FORMAT)
                  # if the checksum is wrong, this statement raises
                  self.RESPONSE.decompose(response_frame)

              # did we get the right response to our query?
              if self.SEQUENCE != self.RESPONSE.SEQUENCE:
                  raise WrongResponseSequence

  Basic structure of a query to get or set a parameter. Has the attribute RESPONSE which contains the answer received by the device. The response is set via set_response

  To be initialized with a target device address (default=broadcast), the channel, teh sequence number and a Parameter() instance of the corresponding parameter. :param parameter: Parameter :param sequence: int :param address: int :param parameter_instance: int

  ### Ancestors

  - MeFrame

  ### Subclasses

  - IF
  - RS
  - SP
  - VR
  - VS

  ### Methods

  `def set_response(self, response_frame)`
    Expand source code

        def set_response(self, response_frame):
            """
            Takes the bytes received from the device as input and creates the corresponding response instance.
            :param response_frame: bytes
            :return:
            """
            # check the type of the response
            # is it an ACK packet?
            if len(response_frame) == 10:
                self.RESPONSE = ACK()
                self.RESPONSE.decompose(response_frame)
            # is it an info string packet/response_frame does not contain source (!)
            elif len(response_frame) == 30:
                self.RESPONSE = IFResponse()
                self.RESPONSE.decompose(response_frame)
            # is it an error packet?
            elif b'+' in response_frame:
                self.RESPONSE = DeviceError()
                self.RESPONSE.decompose(response_frame)
            # nope it's a response to a parameter query
            else:
                self.RESPONSE = VRResponse(self._RESPONSE_FORMAT)
                # if the checksum is wrong, this statement raises
                self.RESPONSE.decompose(response_frame)

            # did we get the right response to our query?
            if self.SEQUENCE != self.RESPONSE.SEQUENCE:
                raise WrongResponseSequence

    Takes the bytes received from the device as input and creates the corresponding response instance. :param response_frame: bytes :return:

  ### Inherited members

  - `MeFrame`:
    - `CalcCRC_CCITT`
    - `compose`
    - `crc`
`class RS (address=0)`
  Expand source code

      class RS(Query):
          """
          Implementing system reset.
          """
          _PAYLOAD_START = 'RS'

          def __init__(self, address=0):
              """
              Create a query to set a parameter value.
              :param address: int
              :param parameter_instance: int
              """

              # init header
              super(RS, self).__init__(parameter=None, address=address)

              # no need to initialize response format, we want ACK

  Implementing system reset.

  Create a query to set a parameter value. :param address: int :param parameter_instance: int

  ### Ancestors

  - Query
  - MeFrame

  ### Inherited members

  - `Query`:
    - `CalcCRC_CCITT`
    - `compose`
    - `crc`
    - `set_response`
`class SP (address=0)`
  Expand source code

      class SP(Query):
          """
          Implementing query to save all parameter values to flash.
          """
          _PAYLOAD_START = 'SP'

          def __init__(self, address=0):
              """
              Create a query to set a parameter value.
              :param address: int
              """

              # init header
              super(SP, self).__init__(parameter=None, address=address)

              # no need to initialize response format, we want ACK

  Implementing query to save all parameter values to flash.

  Create a query to set a parameter value. :param address: int

  ### Ancestors

  - Query
  - MeFrame

  ### Inherited members

  - `Query`:
    - `CalcCRC_CCITT`
    - `compose`
    - `crc`
    - `set_response`
`class VR (parameter, address=0, parameter_instance=1)`
  Expand source code

      class VR(Query):
          """
          Implementing query to get a parameter from the device (?VR).
          """
          _PAYLOAD_START = "?VR"

          def __init__(self, parameter, address=0, parameter_instance=1):
              """
              Create a query to get a parameter value.
              :param parameter: Parameter
              :param address: int
              :param parameter_instance: int
              """
              # init header (equal for get and set queries
              super(VR, self).__init__(parameter=parameter,
                               address=address,
                               parameter_instance=parameter_instance)
              # initialize response
              assert parameter.format in self._TYPES.keys()

              self._RESPONSE_FORMAT = parameter.format

  Implementing query to get a parameter from the device (?VR).

  Create a query to get a parameter value. :param parameter: Parameter :param address: int :param parameter_instance: int

  ### Ancestors

  - Query
  - MeFrame

  ### Inherited members

  - `Query`:
    - `CalcCRC_CCITT`
    - `compose`
    - `crc`
    - `set_response`
`class VRResponse (response_format)`
  Expand source code

      class VRResponse(MeFrame):
          """
          Frame for the device response to a VR() query.
          """
          _SOURCE = "!"
          _RESPONSE_FORMAT = None

          def __init__(self, response_format):
              """
              The format of the response is given via VR.set_response()
              :param response_format: str
              """
              super(VRResponse, self).__init__()
              self._RESPONSE_FORMAT = self._TYPES[response_format]

          def decompose(self, frame_bytes):
              """
              Takes bytes as input and builds the instance.
              :param frame_bytes: bytes
              :return:
              """
              assert self._RESPONSE_FORMAT is not None
              frame_bytes = self._SOURCE.encode() + frame_bytes
              self._decompose_header(frame_bytes)

              frame = frame_bytes.decode()
              self.PAYLOAD = [unpack(self._RESPONSE_FORMAT, bytes.fromhex(frame[7:15]))[0]]  # convert hex to float or int
              self.crc(int(frame[-4:], 16))  # sets crc or raises

  Frame for the device response to a VR() query.

  The format of the response is given via VR.set_response() :param response_format: str

  ### Ancestors

  - MeFrame

  ### Methods

  `def decompose(self, frame_bytes)`
    Expand source code

        def decompose(self, frame_bytes):
            """
            Takes bytes as input and builds the instance.
            :param frame_bytes: bytes
            :return:
            """
            assert self._RESPONSE_FORMAT is not None
            frame_bytes = self._SOURCE.encode() + frame_bytes
            self._decompose_header(frame_bytes)

            frame = frame_bytes.decode()
            self.PAYLOAD = [unpack(self._RESPONSE_FORMAT, bytes.fromhex(frame[7:15]))[0]]  # convert hex to float or int
            self.crc(int(frame[-4:], 16))  # sets crc or raises

    Takes bytes as input and builds the instance. :param frame_bytes: bytes :return:

  ### Inherited members

  - `MeFrame`:
    - `CalcCRC_CCITT`
    - `compose`
    - `crc`
`class VS (value, parameter, address=0, parameter_instance=1)`
  Expand source code

      class VS(Query):
          """
          Implementing query to set a parameter from the device (VS).
          """
          _PAYLOAD_START = "VS"

          def __init__(self, value, parameter, address=0, parameter_instance=1):
              """
              Create a query to set a parameter value.
              :param value: int or float
              :param parameter: Parameter
              :param address: int
              :param parameter_instance: int
              """
              # init header (equal for get and set queries)
              super(VS, self).__init__(parameter=parameter,
                               address=address,
                               parameter_instance=parameter_instance)

              # cast the value parameter to the correct type
              conversions = {'FLOAT32': float, 'INT32': int}
              assert parameter.format in conversions.keys()

              value=conversions[parameter.format](value)

              # the set value
              self.PAYLOAD.append(value)

              # no need to initialize response format, we want ACK

  Implementing query to set a parameter from the device (VS).

  Create a query to set a parameter value. :param value: int or float :param parameter: Parameter :param address: int :param parameter_instance: int

  ### Ancestors

  - Query
  - MeFrame

  ### Inherited members

  - `Query`:
    - `CalcCRC_CCITT`
    - `compose`
    - `crc`
    - `set_response`