Esempio n. 1
0
 def get_power(self):
     """Return the current AC power in Watts using Scale factor which sets decimal point"""
     reg = self.read_registers(83, 2)
     scale = minimalmodbus._twoByteStringToNum(
         minimalmodbus._numToTwoByteString(reg[1]), signed=True)
     power = minimalmodbus._twoByteStringToNum(
         minimalmodbus._numToTwoByteString(reg[0]), abs(scale), signed=True)
     return power
Esempio n. 2
0
    def read_bits(self, registeraddress, functioncode=2):
        """Read multiple bits from the slave.

        Args:
            * registeraddress (int): The slave register address (use decimal numbers, not hex).
            * functioncode (int): Modbus function code. Can be 1 or 2.

        Returns:
            The bits value (int).
        """
        payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                        minimalmodbus._numToTwoByteString(4)
        payloadFromSlave = self._performCommand(functioncode, payloadToSlave)
        minimalmodbus._checkResponseByteCount(payloadFromSlave)
        registerdata = payloadFromSlave[1:]
        return int(minimalmodbus._hexlify(registerdata))
Esempio n. 3
0
    def get_multiple_detector_levels(self, detector_numbers):
        """Get the levels for multiple detectors in one communication call

        Args:
            detector_numbers (sequence): Sequence of integer detector numbers (remembe
                they are 1 based)

        .. warning::
           This method uses "hidden" functions in the minimal modbus module for value
           conversion. As they are hidden, they are not guarantied to preserve their
           interface, which means that this method may break at any time

        """
        # Check for valid detector numbers
        for detector_number in detector_numbers:
            self._check_detector_number(detector_number)

        # We read 10 registers per detector
        # FIXME. This may exceed the maximum number of registers that can be read
        data = self.read_registers(2999, len(detector_numbers) * 10)

        detector_levels = {}
        for detector_number in detector_numbers:
            # Calculate the register shift for this detector. There are 10 registers
            # per detector, in order.
            reg_shift = 10 * (detector_number - 1)

            # Get the range and read the level
            detector_range = self.detector_configuration(detector_number).range
            # The level is the 0th register
            level_register = data[reg_shift]
            bytestring = _numToTwoByteString(level_register)
            level = _twoByteStringToNum(bytestring, numberOfDecimals=3, signed=True)\
                    * detector_range

            # Status is the 1st register (0-based)
            status = data[1 + reg_shift]
            status_out = []
            if status == 0:
                status_out.append('OK')
            else:
                # Format the number into bitstring and reverse it with [::-1]
                bit_string = '{:016b}'.format(status)[::-1]
                for bit_position, status_message in DETECTOR_STATUS.items():
                    if bit_string[bit_position] == '1':
                        status_out.append(status_message)

            # inhibit is the 4th register (0-based)
            inhibited_register = data[4 + reg_shift]
            inhibited = register_to_bool(inhibited_register)

            # Form the detector levels named tuple and put in output dict
            detector_level = DetLev(detector_number, level, status_out,
                                    inhibited)
            detector_levels[detector_number] = detector_level

        return detector_levels
Esempio n. 4
0
    def get_multiple_detector_levels(self, detector_numbers):
        """Get the levels for multiple detectors in one communication call

        Args:
            detector_numbers (sequence): Sequence of integer detector numbers (remembe
                they are 1 based)

        .. warning::
           This method uses "hidden" functions in the minimal modbus module for value
           conversion. As they are hidden, they are not guarantied to preserve their
           interface, which means that this method may break at any time

        """
        # Check for valid detector numbers
        for detector_number in detector_numbers:
            self._check_detector_number(detector_number)

        # We read 10 registers per detector
        # FIXME. This may exceed the maximum number of registers that can be read
        data = self.read_registers(2999, len(detector_numbers) * 10)

        detector_levels = {}
        for detector_number in detector_numbers:
            # Calculate the register shift for this detector. There are 10 registers
            # per detector, in order.
            reg_shift = 10 * (detector_number - 1)

            # Get the range and read the level
            detector_range = self.detector_configuration(detector_number).range
            # The level is the 0th register
            level_register = data[reg_shift]
            bytestring = _numToTwoByteString(level_register)
            level = _twoByteStringToNum(bytestring, numberOfDecimals=3, signed=True)\
                    * detector_range

            # Status is the 1st register (0-based)
            status = data[1 + reg_shift]
            status_out = []
            if status == 0:
                status_out.append('OK')
            else:
                # Format the number into bitstring and reverse it with [::-1]
                bit_string = '{:016b}'.format(status)[::-1]
                for bit_position, status_message in DETECTOR_STATUS.items():
                    if bit_string[bit_position] == '1':
                        status_out.append(status_message)

            # inhibit is the 4th register (0-based)
            inhibited_register = data[4 + reg_shift]
            inhibited = register_to_bool(inhibited_register)

            # Form the detector levels named tuple and put in output dict
            detector_level = DetLev(detector_number, level, status_out, inhibited)
            detector_levels[detector_number] = detector_level

        return detector_levels
Esempio n. 5
0
    def get_power(self):
	"""Return the current AC power in Watts using Scale factor which sets decimal point"""
	reg = self.read_registers(83,2)
	scale = minimalmodbus._twoByteStringToNum(minimalmodbus._numToTwoByteString(reg[1]), signed=True)
	power = minimalmodbus._twoByteStringToNum(minimalmodbus._numToTwoByteString(reg[0]), abs(scale), signed=True)
	return power
Esempio n. 6
0
    def _genericCommand(self, functioncode, registeraddress, value=None, \
            numberOfDecimals=0, numberOfRegisters=1, signed=False, payloadformat=None):
        """Generic command for reading and writing registers and bits.
        Args:
            * functioncode (int): Modbus function code.
            * registeraddress (int): The register address  (use decimal numbers, not hex).
            * value (numerical or string or None or list of int): The value to store in the register. Depends on payloadformat.
            * numberOfDecimals (int): The number of decimals for content conversion. Only for a single register.
            * numberOfRegisters (int): The number of registers to read/write. Only certain values allowed, depends on payloadformat.
            * signed (bool): Whether the data should be interpreted as unsigned or signed. Only for a single register or for payloadformat='long'.
            * payloadformat (None or string): None, 'long', 'float', 'string', 'register', 'registers'. Not necessary for single registers or bits.
        If a value of 77.0 is stored internally in the slave register as 770,
        then use ``numberOfDecimals=1`` which will divide the received data from the slave by 10
        before returning the value. Similarly ``numberOfDecimals=2`` will divide
        the received data by 100 before returning the value. Same functionality is also used
        when writing data to the slave.
        Returns:
            The register data in numerical value (int or float), or the bit value 0 or 1 (int), or ``None``.
        Raises:
            ValueError, TypeError, IOError
        """
        NUMBER_OF_BITS = 1
        NUMBER_OF_BYTES_FOR_ONE_BIT = 1
        NUMBER_OF_BYTES_BEFORE_REGISTERDATA = 1
        ALL_ALLOWED_FUNCTIONCODES = list(range(
            1, 7)) + [15, 16] + [22]  # To comply with both Python2 and Python3
        MAX_NUMBER_OF_REGISTERS = 255

        # Payload format constants, so datatypes can be told apart.
        # Note that bit datatype not is included, because it uses other functioncodes.
        PAYLOADFORMAT_LONG = 'long'
        PAYLOADFORMAT_FLOAT = 'float'
        PAYLOADFORMAT_STRING = 'string'
        PAYLOADFORMAT_REGISTER = 'register'
        PAYLOADFORMAT_REGISTERS = 'registers'

        ALL_PAYLOADFORMATS = [PAYLOADFORMAT_LONG, PAYLOADFORMAT_FLOAT, \
            PAYLOADFORMAT_STRING, PAYLOADFORMAT_REGISTER, PAYLOADFORMAT_REGISTERS]

        ## Check input values ##
        minimalmodbus._checkFunctioncode(
            functioncode, ALL_ALLOWED_FUNCTIONCODES
        )  # Note: The calling facade functions should validate this
        minimalmodbus._checkRegisteraddress(registeraddress)
        minimalmodbus._checkInt(numberOfDecimals,
                                minvalue=0,
                                description='number of decimals')
        minimalmodbus._checkInt(numberOfRegisters,
                                minvalue=1,
                                maxvalue=MAX_NUMBER_OF_REGISTERS,
                                description='number of registers')
        minimalmodbus._checkBool(signed, description='signed')

        if payloadformat is not None:
            if payloadformat not in ALL_PAYLOADFORMATS:
                raise ValueError(
                    'Wrong payload format variable. Given: {0!r}'.format(
                        payloadformat))

        ## Check combinations of input parameters ##
        numberOfRegisterBytes = numberOfRegisters * _NUMBER_OF_BYTES_PER_REGISTER

        # Payload format
        if functioncode in [3, 4, 6, 16] and payloadformat is None:
            payloadformat = PAYLOADFORMAT_REGISTER

        if functioncode in [3, 4, 6, 16]:
            if payloadformat not in ALL_PAYLOADFORMATS:
                raise ValueError('The payload format is unknown. Given format: {0!r}, functioncode: {1!r}.'.\
                    format(payloadformat, functioncode))
        else:
            if payloadformat is not None:
                raise ValueError('The payload format given is not allowed for this function code. ' + \
                    'Given format: {0!r}, functioncode: {1!r}.'.format(payloadformat, functioncode))

                # Signed and numberOfDecimals
        if signed:
            if payloadformat not in [
                    PAYLOADFORMAT_REGISTER, PAYLOADFORMAT_LONG
            ]:
                raise ValueError('The "signed" parameter can not be used for this data format. ' + \
                    'Given format: {0!r}.'.format(payloadformat))

        if numberOfDecimals > 0 and payloadformat != PAYLOADFORMAT_REGISTER:
            raise ValueError('The "numberOfDecimals" parameter can not be used for this data format. ' + \
                'Given format: {0!r}.'.format(payloadformat))

            # Number of registers
        if functioncode not in [3, 4, 16] and numberOfRegisters != 1:
            raise ValueError('The numberOfRegisters is not valid for this function code. ' + \
                'NumberOfRegisters: {0!r}, functioncode {1}.'.format(numberOfRegisters, functioncode))

        if functioncode == 16 and payloadformat == PAYLOADFORMAT_REGISTER and numberOfRegisters != 1:
            raise ValueError('Wrong numberOfRegisters when writing to a ' + \
                'single register. Given {0!r}.'.format(numberOfRegisters))
            # Note: For function code 16 there is checking also in the content conversion functions.

            # Value
        if functioncode in [5, 6, 15, 16, 22] and value is None:
            raise ValueError('The input value is not valid for this function code. ' + \
                'Given {0!r} and {1}.'.format(value, functioncode))

        if functioncode == 16 and payloadformat in [
                PAYLOADFORMAT_REGISTER, PAYLOADFORMAT_FLOAT, PAYLOADFORMAT_LONG
        ]:
            minimalmodbus._checkNumerical(value, description='input value')

        if functioncode == 6 and payloadformat == PAYLOADFORMAT_REGISTER:
            minimalmodbus._checkNumerical(value, description='input value')

            # Value for string
        if functioncode == 16 and payloadformat == PAYLOADFORMAT_STRING:
            minimalmodbus._checkString(value,
                                       'input string',
                                       minlength=1,
                                       maxlength=numberOfRegisterBytes)
            # Note: The string might be padded later, so the length might be shorter than numberOfRegisterBytes.

            # Value for registers
        if functioncode == 16 and payloadformat == PAYLOADFORMAT_REGISTERS:
            if not isinstance(value, list):
                raise TypeError(
                    'The value parameter must be a list. Given {0!r}.'.format(
                        value))

            if len(value) != numberOfRegisters:
                raise ValueError('The list length does not match number of registers. ' + \
                    'List: {0!r},  Number of registers: {1!r}.'.format(value, numberOfRegisters))

        ## Build payload to slave ##
        if functioncode in [1, 2]:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(NUMBER_OF_BITS)

        elif functioncode in [3, 4]:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(numberOfRegisters)

        elif functioncode == 5:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._createBitpattern(functioncode, value)

        elif functioncode == 6:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(value, numberOfDecimals, signed=signed)

        elif functioncode == 15:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(NUMBER_OF_BITS) + \
                            minimalmodbus._numToOneByteString(NUMBER_OF_BYTES_FOR_ONE_BIT) + \
                            minimalmodbus._createBitpattern(functioncode, value)

        elif functioncode == 16:
            if payloadformat == PAYLOADFORMAT_REGISTER:
                registerdata = minimalmodbus._numToTwoByteString(
                    value, numberOfDecimals, signed=signed)

            elif payloadformat == PAYLOADFORMAT_STRING:
                registerdata = minimalmodbus._textstringToBytestring(
                    value, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_LONG:
                registerdata = minimalmodbus._longToBytestring(
                    value, signed, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_FLOAT:
                registerdata = minimalmodbus._floatToBytestring(
                    value, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_REGISTERS:
                registerdata = minimalmodbus._valuelistToBytestring(
                    value, numberOfRegisters)

            assert len(registerdata) == numberOfRegisterBytes
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(numberOfRegisters) + \
                            minimalmodbus._numToOneByteString(numberOfRegisterBytes) + \
                            registerdata
        elif functioncode == 22:
            registerdata = minimalmodbus._valuelistToBytestring(value, 2)
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            registerdata
        ## Communicate ##
        payloadFromSlave = self._performCommand(functioncode, payloadToSlave)

        ## Check the contents in the response payload ##
        if functioncode in [1, 2, 3, 4]:
            minimalmodbus._checkResponseByteCount(
                payloadFromSlave)  # response byte count

        if functioncode in [5, 6, 15, 16]:
            minimalmodbus._checkResponseRegisterAddress(
                payloadFromSlave, registeraddress)  # response register address

        if functioncode == 5:
            minimalmodbus._checkResponseWriteData(
                payloadFromSlave,
                minimalmodbus._createBitpattern(functioncode,
                                                value))  # response write data

        if functioncode == 6:
            minimalmodbus._checkResponseWriteData(payloadFromSlave, \
                minimalmodbus._numToTwoByteString(value, numberOfDecimals, signed=signed))  # response write data

        if functioncode == 15:
            minimalmodbus._checkResponseNumberOfRegisters(
                payloadFromSlave, NUMBER_OF_BITS)  # response number of bits

        if functioncode == 16:
            minimalmodbus._checkResponseNumberOfRegisters(
                payloadFromSlave,
                numberOfRegisters)  # response number of registers

        ## Calculate return value ##
        if functioncode in [1, 2]:
            registerdata = payloadFromSlave[
                NUMBER_OF_BYTES_BEFORE_REGISTERDATA:]
            if len(registerdata) != NUMBER_OF_BYTES_FOR_ONE_BIT:
                raise ValueError('The registerdata length does not match NUMBER_OF_BYTES_FOR_ONE_BIT. ' + \
                    'Given {0}.'.format(len(registerdata)))

            return minimalmodbus._bitResponseToValue(registerdata)

        if functioncode in [3, 4]:
            registerdata = payloadFromSlave[
                NUMBER_OF_BYTES_BEFORE_REGISTERDATA:]
            if len(registerdata) != numberOfRegisterBytes:
                raise ValueError('The registerdata length does not match number of register bytes. ' + \
                    'Given {0!r} and {1!r}.'.format(len(registerdata), numberOfRegisterBytes))

            if payloadformat == PAYLOADFORMAT_STRING:
                return minimalmodbus._bytestringToTextstring(
                    registerdata, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_LONG:
                return minimalmodbus._bytestringToLong(registerdata, signed,
                                                       numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_FLOAT:
                return minimalmodbus._bytestringToFloat(
                    registerdata, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_REGISTERS:
                return minimalmodbus._bytestringToValuelist(
                    registerdata, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_REGISTER:
                return minimalmodbus._twoByteStringToNum(registerdata,
                                                         numberOfDecimals,
                                                         signed=signed)

            raise ValueError('Wrong payloadformat for return value generation. ' + \
                'Given {0}'.format(payloadformat))

        if functioncode == 22:
            registerdata = payloadFromSlave[
                NUMBER_OF_BYTES_BEFORE_REGISTERDATA:]
            return ("OK")
Esempio n. 7
0
 def convert_MODbus_to_standard_float(self, a):
     if len(a) != 2:
         raise Exception('INVALID input')
     b = [a[1], a[0]]
     return minimalmodbus._bytestringToFloat("".join(
         [minimalmodbus._numToTwoByteString(i) for i in b]))