Пример #1
0
def readMBinputs(clientIP, coil, number=1):

    from pymodbus.client.sync import ModbusTcpClient, ConnectionException

    client = ModbusTcpClient(clientIP)
    values = []
    try:
        rawresult = client.read_discrete_inputs(coil, number)

    except ConnectionException:
        # print('we were unable to connect to the host')
        statuscode = 7
    else:
        # print(rawresult)
        try:
            resultregisters = rawresult.bits[0:number]
        except AttributeError:
            statuscode = rawresult.exception_code
        else:
            statuscode = 0
            values = resultregisters
    client.close()
    result = {
        'message': messagefrommbstatuscode(statuscode),
        'statuscode': statuscode,
        'values': values
    }
    return result
Пример #2
0
 def read_discrete_inputs(self, command):
     parser = argument_parser()
     command = 'read_discrete_inputs ' + command
     spec = parser.parse_args(command.split())
     response = _ModbusClient.read_discrete_inputs(
         self, spec.address, spec.count, unit=spec.unit_id)
     return response
Пример #3
0
class Client:
    def __init__(self):
        self.client = None
        self.handle = None
        self.ip = '127.0.0.1'
        self.port = 502

    def setup(self, config):
        self.handle = config
        self.ip = config['ipv4']['value']
        self.port = config['port']['value']
        self.client = ModbusTcpClient(self.ip, self.port)

    def execute(self, fc, addr, length=1, values=None):
        result = None
        if fc == 1:
            temp = self.client.read_coils(addr, length)
            result = []
            for i in range(temp.byte_count):
                t2 = temp.bits[i * 16:(i + 1) * 16]
                result.append(''.join([str(int(x)) for x in t2]))
        elif fc == 2:
            temp = self.client.read_discrete_inputs(addr, length)
            result = []
            for i in range(temp.byte_count):
                t2 = temp.bits[i * 16:(i + 1) * 16]
                result.append(''.join([str(int(x)) for x in t2]))
        elif fc == 3:
            temp = self.client.read_holding_registers(addr, length).registers
            result = ['{0:016b}'.format(x) for x in temp]
        elif fc == 4:
            temp = self.client.read_input_registers(addr, length).registers
            result = ['{0:016b}'.format(x) for x in temp]
        elif fc == 5:
            if values:
                self.client.write_coil(addr, values[0])
        elif fc == 6:
            if values:
                self.client.write_register(addr, values[0])
        elif fc == 15:
            if values:
                self.client.write_coils(addr, values)
        elif fc == 16:
            if values:
                self.client.write_registers(addr, values)
        return result

    def update_config(self, conf):
        self.ip = conf['ipv4']['value']
        self.port = conf['port']['value']
        self.client = ModbusTcpClient(self.ip, self.port)
        self.handle = conf

    def connect(self):
        return self.client.connect()
Пример #4
0
    def post(self):
        query = self.reqparse.parse_args()
        client = ModbusClient(query['ip'], query['port'])
        client.connect()

        data = None
        start_address = query['start_address']
        count = query['count']
        if query['type_prefix'] == ModbusTypePrefix.DISCRETE_INPUT.value:
            data = client.read_discrete_inputs(start_address, count, unit=1)
        elif query['type_prefix'] == ModbusTypePrefix.COIL.value:
            data = client.read_coils(start_address, count, unit=1)
        elif query['type_prefix'] == ModbusTypePrefix.INPUT_REGISTER.value:
            data = client.read_input_registers(start_address, count, unit=1)
        elif query['type_prefix'] == ModbusTypePrefix.HOLDING_REGISTER.value:
            data = client.read_holding_registers(start_address, count, unit=1)

        client.close()

        result = []

        print(data.registers)
        # if hasattr(data, 'bits'):
        #     d = data.bits
        # else:
        #     d = data.registers

        decoder = BinaryPayloadDecoder.fromRegisters(data.registers,
                                                     byteorder=Endian.Big,
                                                     wordorder=Endian.Big)
        # decoder.reset()
        # decoded = {
        #     'string': decoder.decode_string(8),
        #     'float': decoder.decode_32bit_float(),
        #     '16uint': decoder.decode_16bit_uint(),
        #     'ignored': decoder.skip_bytes(2),
        #     '8int': decoder.decode_8bit_int(),
        #     'bits': decoder.decode_bits(),
        # }
        e = decoder.decode_16bit_int()
        i = 0
        while e is not False:
            try:
                print e
                result.append({'address': i + start_address, 'value': e})
                i += 1
                e = decoder.decode_16bit_int()
            except:
                e = False

        # for i, v in enumerate(d):
        #     result.append({'address': i+start_address, 'value': v})

        reg_fields = {'address': fields.Integer, 'value': fields.Integer}
        return {'registers': [marshal(reg, reg_fields) for reg in result]}
Пример #5
0
class ChattySensor():
    def __init__(self, BIT_NUMBER=0, RESOLUTION=3):
        self.BIT_NUMBER = BIT_NUMBER
        self.client = ModbusTcpClient('127.0.0.1')
        self.encoded_message = []
        self.last_value = ''
        self.delayed_time = 0
        self.data = ''
        self.index = 0
        self.RESOLUTION = RESOLUTION

    def get_data(self):
        return self.data

    def next_bit(self):
        self.index = self.index + 1
        self.index = self.index % len(COVERT_MESSAGE)

    def get_measure(self):
        if random.randint(0, 3) == 0:
            return True

        result = self.client.read_discrete_inputs(self.BIT_NUMBER, 1)
        current_value = result.bits[0]
        if self.last_value != '' and self.last_value == True and current_value == False:
            current_time = int(
                str(time.time()).split('.')[1][:self.RESOLUTION])
            if int(COVERT_MESSAGE[self.index]) == current_time % 2:
                delta_time = int(str(
                    time.time()).split('.')[1][:3]) - self.delayed_time
                self.data = "\t".join([
                    "Chatty Sensor:",
                    str(current_time), COVERT_MESSAGE[self.index],
                    str(delta_time)
                ])
                self.encoded_message.append(
                    str(time.time()).split('.')[1][:self.RESOLUTION])
                self.last_value = current_value
            else:
                current_value = self.last_value
                self.delayed_time = int(str(time.time()).split('.')[1][:3])
        else:
            self.delayed_time = int(str(time.time()).split('.')[1][:3])
            self.last_value = current_value

        return current_value

    def __del__(self):
        self.client.close()
Пример #6
0
def readMBinputs(clientIP, coil, number=1):

    from pymodbus.client.sync import ModbusTcpClient, ConnectionException

    client = ModbusTcpClient(clientIP)
    values = []
    try:
        rawresult = client.read_discrete_inputs(coil, number)

    except ConnectionException:
        # print('we were unable to connect to the host')
        statuscode = 7
    else:
        # print(rawresult)
        try:
            resultregisters = rawresult.bits[0:number]
        except AttributeError:
            statuscode = rawresult.exception_code
        else:
            statuscode = 0
            values = resultregisters
    client.close()
    result = {'message': messagefrommbstatuscode(statuscode), 'statuscode': statuscode, 'values':values}
    return result
Пример #7
0
    def activate(self):
        rospy.init_node('niryo_node', anonymous=False)
        while not rospy.is_shutdown():
            if (self.activate_plc == "Activated"):
                rospy.loginfo(
                    "Niryo will do other action, PLC will be deactivated")
                self.pub.publish("plc_deactivate")
            else:
                rospy.loginfo(
                    "PLC hasn't been activated, Niryo will activate PLC")
                self.pub.publish("Activate_plc")
            client = ModbusClient("192.168.1.7", port=502)
            client.connect()
            UNIT = 0x1
            print("Escritura de salidas")
            rq = client.write_coil(0, [True] * 8, unit=UNIT)
            rr = client.read_coils(0, 8, unit=UNIT)
            print("Las salidas Q0.0-Q0.7 ", rr.bits)

            print("Leer entradas")
            rr = client.read_discrete_inputs(0, 8, unit=UNIT)
            print("Las entradas I0.0-I0.7 son ", rr.bits)
            print("Escritura de un HR")
            rq = client.write_register(0, 15, unit=UNIT)
            rr = client.read_holding_registers(0, 1, unit=UNIT)
            print("HR0 = ", rr.registers)
            print("Escritura de varios HR")
            rq = client.write_registers(1, [35] * 10, unit=UNIT)
            rr = client.read_holding_registers(1, 10, unit=UNIT)
            print("HR0 = ", rr.registers)
            print("Escritura de varios HR")
            rq = client.write_registers(11, [43] * 5, unit=UNIT)
            rr = client.read_holding_registers(0, 15, unit=UNIT)
            print("HR0 = ", rr.registers)
            client.close()
            rospy.sleep(1)
Пример #8
0
from pymodbus.client.sync import ModbusTcpClient as ModbusClient

client = ModbusClient('127.0.0.1', 5020)
print(client)
client.connect()
#holding registers:
rr = client.read_holding_registers(0, 2, unit=1)  #read AO
A = rr.registers
print(A)
#discrete inputs:
rr = client.read_discrete_inputs(
    0, 7, unit=1)  #will reply 1 byte --> 8 bits被數到的打開遮罩,沒數到的被遮罩
B = rr.bits
print(B)
#coil read:
rr = client.read_coils(0, 8, unit=1)  #被數到的打開遮罩,沒數到的被遮罩
C = rr.bits
print(C)
#input registers:
rr = client.read_input_registers(0, 2, unit=1)  #read AI
D = rr.registers
print(D)

print('==== AI ====')
#-- FC04: read multi-input registers (3xxxx), for AI
#read_input_registers(start_addr, count, unit=sid)
rr = client.read_input_registers(0, 1, unit=1)  #read AI
print(rr, "value=", rr.registers)
rr = client.read_input_registers(0, 2, unit=1)  #read AI
print(rr, "value=", rr.registers)
Пример #9
0
def run_sync_client():
    # ------------------------------------------------------------------------#
    # choose the client you want
    # ------------------------------------------------------------------------#
    # make sure to start an implementation to hit against. For this
    # you can use an existing device, the reference implementation in the tools
    # directory, or start a pymodbus server.
    #
    # If you use the UDP or TCP clients, you can override the framer being used
    # to use a custom implementation (say RTU over TCP). By default they use
    # the socket framer::
    #
    #    client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    #
    # It should be noted that you can supply an ipv4 or an ipv6 host address
    # for both the UDP and TCP clients.
    #
    # There are also other options that can be set on the client that controls
    # how transactions are performed. The current ones are:
    #
    # * retries - Specify how many retries to allow per transaction (default=3)
    # * retry_on_empty - Is an empty response a retry (default = False)
    # * source_address - Specifies the TCP source address to bind to
    # * strict - Applicable only for Modbus RTU clients.
    #            Adheres to modbus protocol for timing restrictions
    #            (default = True).
    #            Setting this to False would disable the inter char timeout
    #            restriction (t1.5) for Modbus RTU
    #
    #
    # Here is an example of using these options::
    #
    #    client = ModbusClient('localhost', retries=3, retry_on_empty=True)
    # ------------------------------------------------------------------------#
    client = ModbusClient('localhost', port=5020)
    # from pymodbus.transaction import ModbusRtuFramer
    # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    # client = ModbusClient(method='binary', port='/dev/ptyp0', timeout=1)
    # client = ModbusClient(method='ascii', port='/dev/ptyp0', timeout=1)
    # client = ModbusClient(method='rtu', port='/dev/ptyp0', timeout=1,
    #                       baudrate=9600)
    client.connect()

    # ------------------------------------------------------------------------#
    # specify slave to query
    # ------------------------------------------------------------------------#
    # The slave to query is specified in an optional parameter for each
    # individual request. This can be done by specifying the `unit` parameter
    # which defaults to `0x00`
    # ----------------------------------------------------------------------- #
    log.debug("Reading Coils")
    rr = client.read_coils(1, 1, unit=UNIT)
    log.debug(rr)


    # ----------------------------------------------------------------------- #
    # example requests
    # ----------------------------------------------------------------------- #
    # simply call the methods that you would like to use. An example session
    # is displayed below along with some assert checks. Note that some modbus
    # implementations differentiate holding/input discrete/coils and as such
    # you will not be able to write to these, therefore the starting values
    # are not known to these tests. Furthermore, some use the same memory
    # blocks for the two sets, so a change to one is a change to the other.
    # Keep both of these cases in mind when testing as the following will
    # _only_ pass with the supplied asynchronous modbus server (script supplied).
    # ----------------------------------------------------------------------- #
    log.debug("Write to a Coil and read back")
    rq = client.write_coil(0, True, unit=UNIT)
    rr = client.read_coils(0, 1, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.bits[0] == True)          # test the expected value

    log.debug("Write to multiple coils and read back- test 1")
    rq = client.write_coils(1, [True]*8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    rr = client.read_coils(1, 21, unit=UNIT)
    assert(not rr.isError())     # test that we are not an error
    resp = [True]*21

    # If the returned output quantity is not a multiple of eight,
    # the remaining bits in the final data byte will be padded with zeros
    # (toward the high order end of the byte).

    resp.extend([False]*3)
    assert(rr.bits == resp)         # test the expected value

    log.debug("Write to multiple coils and read back - test 2")
    rq = client.write_coils(1, [False]*8, unit=UNIT)
    rr = client.read_coils(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.bits == [False]*8)         # test the expected value

    log.debug("Read discrete inputs")
    rr = client.read_discrete_inputs(0, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error

    log.debug("Write to a holding register and read back")
    rq = client.write_register(1, 10, unit=UNIT)
    rr = client.read_holding_registers(1, 1, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.registers[0] == 10)       # test the expected value

    log.debug("Write to multiple holding registers and read back")
    rq = client.write_registers(1, [10]*8, unit=UNIT)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.registers == [10]*8)      # test the expected value

    log.debug("Read input registers")
    rr = client.read_input_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error

    arguments = {
        'read_address':    1,
        'read_count':      8,
        'write_address':   1,
        'write_registers': [20]*8,
    }
    log.debug("Read write registeres simulataneously")
    rq = client.readwrite_registers(unit=UNIT, **arguments)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rq.registers == [20]*8)      # test the expected value
    assert(rr.registers == [20]*8)      # test the expected value

    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()
class dataValidation(threading.Thread):
    """docstring for dataValidation"""
    def __init__(self):
        super(dataValidation, self).__init__()
        self.threadID = 2
        self.name = 'data_validation'
        self.stoprequest = threading.Event()
        self.begintest = False
        self.testrunning = False
        self.modbusclient = ModbusTcpClient(host='172.28.0.41', port=502)


    def run(self):
        start_test_data = {}
        current_data = {}

        while not self.stoprequest.isSet():
            logger.info('%s' % time.strftime('%Y-%m-%d %H:%M:%S'))
            if self.testrunning: logger.info('Test is in-process')
            else: logger.info('Waiting for test to start')


            try:
                device_data = getJsonData('http://172.28.0.1/latest_data.json')
            except requests.exceptions.ConnectionError:
                logger.error('cannot connect to the site server, check all cable connections.')

            # environmental data
            try:
                licor_constant = -74.73 * 1000

                current_data['irradiance'] = device_data['alpha']['env']['IRRA-1']['irradiance_1'] * licor_constant

                cell_temp = {'A': 1.129241e-3, 'B': 2.341077e-4, 'C': 8.775468e-8}
                cell_temp['v_ratio'] = 5 / device_data['alpha']['env']['cts-1']['cell_temp_01']
                cell_temp['resistance'] = 24900/ (cell_temp['v_ratio'] - 1)
                cell_temp['temperature'] = (1 / (cell_temp['A'] + (cell_temp['B'] * math.log(cell_temp['resistance'])) + (cell_temp['C'] * pow(math.log(cell_temp['resistance']), 3)))) - 273.15

                current_data['cell_temp'] = cell_temp['temperature']

                logger.debug('%s: %s' % (device_data['alpha']['env']['ESI-1']['identifier'], device_data['alpha']['env']['ESI-1']['serial_number']))
                logger.debug('irradiance: %.2f W/m2' % (current_data['irradiance']))
                logger.debug('cell temperature: %.2f Degrees C' % (current_data['cell_temp']))

                if self.begintest:
                    start_test_data['irradiance'] = current_data['irradiance']
                    start_test_data['cell_temp'] = current_data['cell_temp']

                if self.testrunning:
                    logger.info('prev_irradiance: %.2f' % (start_test_data['irradiance']))
                    logger.info('prev_cell_temp: %.2f' % (start_test_data['cell_temp']))

                logger.info('curr_irradiance: %.2f' % (current_data['irradiance']))
                logger.info('curr_cell_temp: %.2f' % (current_data['cell_temp']))

                if self.testrunning:
                    # check env data
                    if (-25 < (start_test_data['irradiance'] - current_data['irradiance']) < 25):
                        logger.info('irradiance value within acceptable limits')
                        logger.debug('difference is: %.2f' % (start_test_data['irradiance'] - current_data['irradiance']))
                    else:
                        logger.error('irradiance value outside of acceptable limits')
                        logger.debug('difference is: %.2f' % (start_test_data['irradiance'] - current_data['irradiance']))

                    if (-5 < (start_test_data['cell_temp'] - current_data['cell_temp']) < 5):
                        logger.info('cell temperature value within acceptable limits')
                        logger.debug('difference is: %.2f' % (start_test_data['cell_temp'] - current_data['cell_temp']))
                    else:
                        logger.error('cell temperature value outside of acceptable limits')
                        logger.debug('difference is: %.2f' % (start_test_data['cell_temp'] - current_data['cell_temp']))

            except KeyError:
                logger.error('ENV data unavailable')

            # MBS-1 data
            try:
                mbs_data = []
                for i in range(1, 11):
                    mbs_data.append(device_data['alpha']['mbs1']['MBS-1']['value%02d' % (i)])
                logger.debug('%s data: %s' % (device_data['alpha']['mbs1']['MBS-1']['identifier'], mbs_data))

                # for i in range(1, 11):
                #     logger.debug('%s data: %s' % (device_data['alpha']['mbs1']['MBS-1']['identifier'], device_data['alpha']['mbs1']['MBS-1']['value%02d' % (i)]))

                if self.testrunning:
                    # check modbus data
                    if checkModbusData('MBS-1', device_data['alpha']['mbs1']['MBS-1']):
                        logger.info('MBS-1: Modbus Data VALID')
                    else:
                        logger.error('MBS-1: Modbus Data INVALID')

            except KeyError:
                logger.error('MBS-1 data unavailable')

            # MBS-2 data
            try:
                mbs_data = []
                for i in range(1, 11):
                    mbs_data.append(device_data['alpha']['mbs2']['MBS-2']['value%02d' % (i)])
                logger.debug('%s data: %s' % (device_data['alpha']['mbs2']['MBS-2']['identifier'], mbs_data))
                # for i in range(1, 11):
                #     logger.debug('%s data: %s' % (device_data['alpha']['mbs2']['MBS-2']['identifier'], device_data['alpha']['mbs2']['MBS-2']['value%02d' % (i)]))

                if self.testrunning:
                    if checkModbusData('MBS-2', device_data['alpha']['mbs2']['MBS-2']):
                        logger.info('MBS-2: Modbus Data VALID')
                    else:
                        logger.error('MBS-2: Modbus Data INVALID')

            except KeyError:
                logger.error('MBS-2 data unavailable')

            #sixnet data
            try:
                # try:
                    if not self.modbusclient.connect():
                        logger.error('failing to connect to sixnet Ethernet switch for Modbus query')

                    sixnet_link_status = self.modbusclient.read_discrete_inputs(0, 8, unit=11)
                    sixnet_pwr_status = self.modbusclient.read_discrete_inputs(29, 3, unit=11)

                    if self.begintest:
                        start_test_data['link_bits'] = sixnet_link_status.bits
                        start_test_data['status_bits'] = sixnet_pwr_status.bits

                    if self.testrunning:
                        logger.debug('prev_link_bits: %s' % (start_test_data['link_bits']))
                        logger.debug('prev_status_bits: %s' % (start_test_data['status_bits']))

                    logger.debug('curr_link_bits: %s' % (sixnet_link_status.bits))
                    logger.debug('curr_status_bits: %s' % (sixnet_pwr_status.bits))


                    if self.testrunning:
                        if start_test_data['link_bits'] != sixnet_link_status.bits:
                            logger.error('sixnet "link" status has changed')
                        elif start_test_data['status_bits'] != sixnet_pwr_status.bits:
                            logger.error('sixnet "OK" status has changed')
                        else:
                            logger.info('sixnet switch status is good')


                # except KeyError:
                    # logger.error('sixnet data unavailable')
            except pymodbus.exceptions.ConnectionException:
                logger.error('Sixnet Modbus query failed')

            if self.begintest:
                self.begintest = False
                self.testrunning = True

            time.sleep(5)
            os.system('clear')

        self.modbusclient.close()

    def join(self, timeout=None):
        if self.testrunning:
            logger.info('Stopping Test...')
            self.testrunning = False

        self.stoprequest.set()
        super(dataValidation, self).join(timeout)

    def starttest(self, timeout=None):
        self.begintest = True

    def stoptest(self, timeout=None):
        self.testrunning = False
Пример #11
0
    numInputs = 10
    startAddress = 1000
    slaveID = 1
    result = client.read_input_registers(startAddress, numInputs, slaveID)

    for i in range(0, len(totusTemps)):
        print totusTemps[i] + " = " + str(
            result.getRegister(i) / 10.0) + "\xb0C"  # scaling is 10

    # read alarms
    totusAlarms = ["ALARM/System/HL/State", "ALARM/System/HHLL/State"]

    numInputs = 2
    startAddress = 100
    slaveID = 1
    result = client.read_discrete_inputs(startAddress, numInputs, slaveID)

    for i in range(0, len(totusAlarms)):
        print totusAlarms[i] + " = " + str(result.getBit(i))

    # read DGA float32 gases
    totusDGA = [
        "DGA/SourceA/CH4", "DGA/SourceA/C2H6", "DGA/SourceA/C2H4",
        "DGA/SourceA/C2H2", "DGA/SourceA/CO", "DGA/SourceA/CO2",
        "DGA/SourceA/O2", "DGA/SourceA/N2", "DGA/SourceA/H2",
        "DGA/SourceA/H2O", "DGA/SourceA/TDCG", "DGA/SourceA/THC"
    ]

    numInputs = 12
    startAddress = 2200
    slaveID = 1
Пример #12
0
def operate(address, port, request, operation):

    # fields of the form
    start = request.form['address']
    value = request.form['value']
    unitId = request.form['unitId']

    # connection to the slave
    port = int(port)
    client = ModbusTcpClient(address, port)
    succeed = client.connect()

    html_template = operation + ".html"

    # no connection
    if not succeed:
        return render_template(
            html_template,
            address=address,
            port=port,
            form=request.form,
            error=
            "Connection has failed. Please, check IP address and port on URL or go back to homepage."
        )

    # operation to launch
    if operation == 'read-discrete-inputs':
        result = client.read_discrete_inputs(address=int(start),
                                             count=int(value),
                                             unit=int(unitId))
    elif operation == 'read-coils':
        result = client.read_coils(address=int(start),
                                   count=int(value),
                                   unit=int(unitId))
    elif operation == 'read-holding-registers':
        result = client.read_holding_registers(address=int(start),
                                               count=int(value),
                                               unit=int(unitId))
    elif operation == 'read-input-registers':
        result = client.read_input_registers(address=int(start),
                                             count=int(value),
                                             unit=int(unitId))
    elif operation == 'write-coil':
        result = client.write_coil(int(start), int(value), unit=int(unitId))
    elif operation == 'write-holding-register':
        result = client.write_register(int(start),
                                       int(value),
                                       unit=int(unitId))

    client.close()

    # error in operation
    if result.isError():
        return render_template(html_template,
                               address=address,
                               port=port,
                               form=request.form,
                               error=result)

    # display results
    else:
        # op : read discrete values
        if operation in ["read-discrete-inputs", "read-coils"]:
            visual_result = []
            for b in result.bits:
                if b:
                    visual_result.append('On')
                else:
                    visual_result.append('Off')
            flash(str(visual_result))

        # op : read registers
        elif operation in ["read-holding-registers", "read-input-registers"]:
            flash(str(result.registers))

        # op : write values
        elif operation in ['write-coil', 'write-holding-register']:
            flash("Success!")

        return render_template(html_template,
                               form=request.form,
                               address=address,
                               port=port)
class ModbusWrapperClient():
    def __init__(self,
                 modbusUnitAddress,
                 maxRegsRead,
                 modbusTimeout,
                 endian="little"):
        self.client = None
        self.modbusAddress = modbusUnitAddress
        self.bufferStart = 0
        self.bufferEnd = 0
        self.data_buffer = None
        self.maxRegsRead = maxRegsRead
        self.timeout = modbusTimeout
        if endian == 'auto':
            self.endian = Endian.Auto
        elif endian == 'little':
            self.endian = Endian.Little
        else:
            self.endian = Endian.Big
        self.isConnected = False
        self.validaddresses = None
        self.validaddresses_write = None

    def openConnectionSerial(self, modbusSerialPort, modbusMethon, modbusByte,
                             modbusStopBits, modbusParity, modbusBaudrate,
                             modbusTimeout):
        self.client = ModbusSerialClient(method=modbusMethon,
                                         port=modbusSerialPort,
                                         stopbits=modbusStopBits,
                                         bytesize=modbusByte,
                                         parity=modbusParity,
                                         baudrate=modbusBaudrate,
                                         timeout=modbusTimeout)
        self.tryReconnect()

    def openConnectionTCP(self, modbusHost, modbusPort):
        self.client = ModbusTcpClient(modbusHost, modbusPort)
        self.tryReconnect()

    def closeConnection(self):
        if self.isConnected is True:
            self.client.close()

    def tryReconnect(self):
        retry = MODBUS_CONNECTIONRETRY + 1
        for i in range(1, retry):
            if self.isConnected is False:
                self.isConnected = self.client.connect()
                break
            log.debug("riconessione %s/%s" % (i, retry))

    def load_valid_addresses(self, lista=None):
        log.debug("load_valid_addresses")
        self.validaddresses = lista

    def check_address(self, address):
        if self.validaddresses is None:
            return True
        ret = True if (address in self.validaddresses) else False
        return ret

    def readRegisters(self,
                      address,
                      count,
                      mb_type='uint16',
                      mb_funcall=3,
                      force=False):
        if self.isConnected is False:
            self.tryReconnect()
        tmp = None
        if (self.check_address(address) is True) or (force is True):
            try:
                if mb_funcall == 1:
                    # Read Coil Status (FC=01)
                    result = self.client.read_coils(address,
                                                    count=count,
                                                    unit=self.modbusAddress)
                    tmp = result.bits
                elif mb_funcall == 2:
                    # Read Dscrete Input (FC=02)
                    result = self.client.read_discrete_inputs(
                        address, count=count, unit=self.modbusAddress)
                    tmp = result.bits
                elif mb_funcall == 3:
                    # Read Holding Registers (FC=03)
                    result = self.client.read_holding_registers(
                        address, count=count, unit=self.modbusAddress)
                    if result != None:
                        tmp = result.registers
                elif mb_funcall == 4:
                    # Read Input Registers (FC=04)
                    result = self.client.read_input_registers(
                        address, count=count, unit=self.modbusAddress)
                    #tmp = result.bits
                    if result != None:
                        tmp = result.registers
                    #log.debug("out: %s" % tmp)
                else:
                    log.debug("Function call not supported: %s" % mb_funcall)
                    result = None
                    tmp = result
            except Exception as e:
                log.exception(e)
        return tmp

    def check_address_write(self, address):
        if self.validaddresses_write is None:
            return True
        ret = True if (address in self.validaddresses_write) else False
        return ret

    def writeRegisters(self,
                       address,
                       value,
                       mb_funcall=5,
                       force=False,
                       skip_encode=False):
        # Refer to "libmodbus" C library: http://libmodbus.org/documentation/
        # log.info('writeRegisters(address="%s", value="%s", mb_funcall="%s"' % (address, value, mb_funcall))
        if self.isConnected is False:
            self.tryReconnect()
        result = None
        if (self.check_address_write(address) is True) or (force is True):
            try:
                if mb_funcall == 5:
                    # Single Coil (FC=05) => modbus_write_bit
                    result = self.client.write_coil(address,
                                                    value,
                                                    unit=self.modbusAddress)
                elif mb_funcall == 6:
                    # Single Register (FC=06)
                    result = self.client.write_register(
                        address,
                        value,
                        unit=self.modbusAddress,
                        skip_encode=skip_encode)
                elif mb_funcall == 15:
                    # Multiple Coils (FC=15) => modbus_write_bits
                    result = self.client.write_coils(address,
                                                     value,
                                                     unit=self.modbusAddress)
                elif mb_funcall == 16:
                    # Multiple Registers (FC=16)
                    result = self.client.write_registers(
                        address,
                        value,
                        unit=self.modbusAddress,
                        skip_encode=skip_encode)
                else:
                    log.warn("Function call not supported: %s" % mb_funcall)
            except Exception as e:
                log.exception(e)
        return result

    def encode_field(self, value, mb_type='unit16'):
        builder = BinaryPayloadBuilder(endian=self.endian)
        if mb_type == 'bit' or mb_type == 'bits':
            builder.add_bits(value)
        elif mb_type == 'uint8':
            builder.add_8bit_uint(value)
        elif mb_type == 'uint16':
            builder.add_16bit_uint(value)
        elif mb_type == 'uint32':
            builder.add_32bit_uint(value)
        elif mb_type == 'uint64':
            builder.add_64bit_uint(value)
        elif mb_type == 'int8':
            builder.add_8bit_int(value)
        elif mb_type == 'int16':
            builder.add_16bit_int(value)
        elif mb_type == 'int32':
            builder.add_32bit_int(value)
        elif mb_type == 'int64':
            builder.add_64bit_int(value)
        elif mb_type == 'float32':
            builder.add_32bit_float(value)
        elif mb_type == 'float64':
            builder.add_64bit_float(value)
        elif mb_type == 'string' or mb_type == 'str':
            builder.add_string(value)
        else:
            log.warn('Not supported DataType: "%s"' % mb_type)
        return builder.build()

    def readRegistersAndDecode(self,
                               registri,
                               counter,
                               mb_type='uint16',
                               mb_funcall=3,
                               force=False):
        tmp = None
        if (self.check_address(registri) is True) or (force is True):
            ret = self.readRegisters(registri, counter, mb_type, mb_funcall,
                                     force)
            if ret is not None:
                tmp = self.decode(ret, counter, mb_type, mb_funcall)
        return tmp

    def decode(self, raw, size, mb_type, mb_funcall=3):
        log.debug('decode param (raw=%s, size=%s, mb_type=%s, mb_funcall=%s)' %
                  (raw, size, mb_type, mb_funcall))
        if mb_funcall == 1:
            # Read Coil Status (FC=01)
            log.debug("decoder FC1 (raw: %s)" % raw)
            decoder = BinaryPayloadDecoder.fromCoils(raw, endian=self.endian)
        elif mb_funcall == 2:
            # Read Discrete Input (FC=02)
            log.debug("decoder FC2 (raw: %s)" % raw)
            decoder = BinaryPayloadDecoder(raw, endian=self.endian)
        elif mb_funcall == 3:
            # Read Holding Registers (FC=03)
            log.debug("decoder FC3 (raw: %s)" % raw)
            decoder = BinaryPayloadDecoder.fromRegisters(raw,
                                                         endian=self.endian)
        elif mb_funcall == 4:
            # Read Input Registers (FC=04)
            log.debug("decoder stub FC4 (raw: %s)" % raw)
            decoder = BinaryPayloadDecoder(raw, endian=self.endian)
        else:
            log.debug("Function call not supported: %s" % mb_funcall)
            decoder = None

        result = ""
        if mb_type == 'bitmap':
            if size == 1:
                mb_type = 'int8'
            elif size == 2:
                mb_type = 'int16'
            elif size == 2:
                mb_type = 'int32'
            elif size == 4:
                mb_type = 'int64'

        if decoder is None:
            log.debug("decode none")
            result = raw
        else:
            try:
                if mb_type == 'string' or mb_type == 'utf8':
                    result = decoder.decode_string(size)
                #elif mb_type == 'bitmap':
                #	result = decoder.decode_string(size)
                elif mb_type == 'datetime':
                    result = decoder.decode_string(size)
                elif mb_type == 'uint8':
                    result = int(decoder.decode_8bit_uint())
                elif mb_type == 'int8':
                    result = int(decoder.decode_8bit_int())
                elif mb_type == 'uint16':
                    result = int(decoder.decode_16bit_uint())
                elif mb_type == 'int16':
                    result = int(decoder.decode_16bit_int())
                elif mb_type == 'uint32':
                    result = int(decoder.decode_32bit_uint())
                elif mb_type == 'int32':
                    result = int(decoder.decode_32bit_int())
                elif mb_type == 'uint64':
                    result = int(decoder.decode_64bit_uint())
                elif mb_type == 'int64':
                    result = int(decoder.decode_64bit_int())
                elif mb_type == 'float32' or mb_type == 'float':
                    result = float(decoder.decode_32bit_float())
                elif mb_type == 'float64':
                    result = float(decoder.decode_64bit_float())
                elif mb_type == 'bit':
                    result = int(decoder.decode_bits())
                elif mb_type == 'bool':
                    result = bool(raw[0])
                elif mb_type == 'raw':
                    result = raw[0]
                else:
                    result = raw
            except ValueError as e:
                log.exception(e)
                result = raw
        return result

    def read1(self, startreg, mb_type, mb_funcall=3):
        return self.readRegisters(startreg, 1, mb_type, mb_funcall)

    def read2(self, startreg, mb_type, mb_funcall=3):
        return self.readRegisters(startreg, 2, mb_type, mb_funcall)

    def read3(self, startreg, mb_type, mb_funcall=3):
        return self.readRegisters(startreg, 3, mb_type, mb_funcall)

    def read4(self, startreg, mb_type, mb_funcall=3):
        return self.readRegisters(startreg, 4, mb_type, mb_funcall)

    def buffer_print(self):
        if not self.bufferReady():
            log.debug('BUFFER empty ---')
        else:
            text = 'BUFFER [%s-%s]: ' % (self.bufferStart, self.bufferEnd)
            i = self.bufferStart
            for item in self.data_buffer:
                text += "%s(%s) " % (i, item)
                i += 1
            log.debug(text)

    def bufferedReadRegisters(self,
                              startreg,
                              counter,
                              mb_type='uint16',
                              mb_funcall=3):
        log.debug(
            'bufferedReadRegisters param (startreg=%s, counter=%s, mb_type=%s, mb_funcall=%s)'
            % (startreg, counter, mb_type, mb_funcall))

        valido = False
        offset = self.maxRegsRead
        while (offset >= 0) and (valido != True):
            valido = self.check_address(startreg + offset)
            if valido is True:
                self.data_buffer = self.readRegisters(startreg, offset,
                                                      mb_type, mb_funcall)
                if self.data_buffer != None:
                    self.bufferStart = startreg
                    self.bufferEnd = startreg + len(self.data_buffer) - 1
            offset -= 1

        self.buffer_print()
        return self.bufferReady()

    def bufferReady(self):
        return True if (self.data_buffer is not None) else False

    def bufferCleanup(self):
        if self.bufferReady():
            self.data_buffer = None

    def inBuffer(self, startreg, conteggio):
        if not self.bufferReady():
            return False
        return True if ((startreg >= self.bufferStart) and
                        ((startreg + conteggio) <= self.bufferEnd)) else False

    def cachedRead(self, startreg, counter, mb_type='uint16', mb_funcall=3):
        log.debug(
            'cachedRead param (startreg=%s, counter=%s, mb_type=%s, mb_funcall=%s)'
            % (startreg, counter, mb_type, mb_funcall))
        if not self.bufferReady():
            self.bufferedReadRegisters(startreg, counter, mb_type, mb_funcall)
        if not self.inBuffer(startreg, counter):
            self.bufferedReadRegisters(startreg, counter, mb_type, mb_funcall)
        regs = []
        i = 0
        while i < counter:
            regs.append(self.data_buffer[startreg - self.bufferStart + i])
            i += 1
        return self.decode(regs, counter, mb_type, mb_funcall)

    def cachedRead1(self, startreg, mb_type='uint16', mb_funcall=3):
        if not self.bufferReady():
            self.bufferedReadRegisters(startreg, 1, mb_type, mb_funcall)
        if not self.inBuffer(startreg, 1):
            self.bufferedReadRegisters(startreg, 1, mb_type, mb_funcall)
        return self.decode(self.data_buffer[startreg - self.bufferStart], 1,
                           mb_type)

    def cachedRead2(self, startreg, mb_type='uint16', mb_funcall=3):
        if not self.bufferReady():
            self.bufferedReadRegisters(startreg, 2, mb_type, mb_funcall)
        if not self.inBuffer(startreg, 2):
            self.bufferedReadRegisters(startreg, 2, mb_type, mb_funcall)

        regs = []
        regs.append(self.data_buffer[startreg - self.bufferStart])
        regs.append(self.data_buffer[startreg - self.bufferStart + 1])
        return self.decode(regs, 2, mb_type)

    def cachedRead3(self, startreg, mb_type='uint16', mb_funcall=3):
        if not self.bufferReady():
            self.bufferedReadRegisters(startreg, 3, mb_type, mb_funcall)
        if not self.inBuffer(startreg, 3):
            self.bufferedReadRegisters(startreg, 3, mb_type, mb_funcall)

        regs = []
        regs.append(self.data_buffer[startreg - self.bufferStart])
        regs.append(self.data_buffer[startreg - self.bufferStart + 1])
        regs.append(self.data_buffer[startreg - self.bufferStart + 2])
        return self.decode(regs, 3, mb_type)

    def cachedRead4(self, startreg, mb_type='uint16', mb_funcall=3):
        if not self.bufferReady():
            self.bufferedReadRegisters(startreg, 4, mb_type, mb_funcall)
        if not self.inBuffer(startreg, 4):
            self.bufferedReadRegisters(startreg, 4, mb_type, mb_funcall)

        regs = []
        regs.append(self.data_buffer[startreg - self.bufferStart])
        regs.append(self.data_buffer[startreg - self.bufferStart + 1])
        regs.append(self.data_buffer[startreg - self.bufferStart + 2])
        regs.append(self.data_buffer[startreg - self.bufferStart + 3])
        return self.decode(regs, 4, mb_type)
Пример #14
0
 def testReadDiscreteInputs(self):
     client = ModbusTcpClient("localhost", 502)
     result = client.read_discrete_inputs(1, 10, unit=1)
     self.assertIsNotNone(result)
     client.close()
Пример #15
0
def run_sync_client():
    # ------------------------------------------------------------------------# 
    # choose the client you want
    # ------------------------------------------------------------------------# 
    # make sure to start an implementation to hit against. For this
    # you can use an existing device, the reference implementation in the tools
    # directory, or start a pymodbus server.
    #
    # If you use the UDP or TCP clients, you can override the framer being used
    # to use a custom implementation (say RTU over TCP). By default they use
    # the socket framer::
    #
    #    client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    #
    # It should be noted that you can supply an ipv4 or an ipv6 host address
    # for both the UDP and TCP clients.
    #
    # There are also other options that can be set on the client that controls
    # how transactions are performed. The current ones are:
    #
    # * retries - Specify how many retries to allow per transaction (default=3)
    # * retry_on_empty - Is an empty response a retry (default = False)
    # * source_address - Specifies the TCP source address to bind to
    #
    # Here is an example of using these options::
    #
    #    client = ModbusClient('localhost', retries=3, retry_on_empty=True)
    # ------------------------------------------------------------------------# 
    client = ModbusClient('localhost', port=5020)
    # client = ModbusClient(method='ascii', port='/dev/pts/2', timeout=1)
    # client = ModbusClient(method='rtu', port='/dev/ttyp0', timeout=1)
    client.connect()
    
    # ------------------------------------------------------------------------# 
    # specify slave to query
    # ------------------------------------------------------------------------# 
    # The slave to query is specified in an optional parameter for each
    # individual request. This can be done by specifying the `unit` parameter
    # which defaults to `0x00`
    # ----------------------------------------------------------------------- #
    log.debug("Reading Coils")
    rr = client.read_coils(1, 1, unit=0x01)
    print(rr)
    
    # ----------------------------------------------------------------------- #
    # example requests
    # ----------------------------------------------------------------------- #
    # simply call the methods that you would like to use. An example session
    # is displayed below along with some assert checks. Note that some modbus
    # implementations differentiate holding/input discrete/coils and as such
    # you will not be able to write to these, therefore the starting values
    # are not known to these tests. Furthermore, some use the same memory
    # blocks for the two sets, so a change to one is a change to the other.
    # Keep both of these cases in mind when testing as the following will
    # _only_ pass with the supplied async modbus server (script supplied).
    # ----------------------------------------------------------------------- #
    log.debug("Write to a Coil and read back")
    rq = client.write_coil(0, True, unit=UNIT)
    rr = client.read_coils(0, 1, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    assert(rr.bits[0] == True)          # test the expected value
    
    log.debug("Write to multiple coils and read back- test 1")
    rq = client.write_coils(1, [True]*8, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    rr = client.read_coils(1, 21, unit=UNIT)
    assert(rr.function_code < 0x80)     # test that we are not an error
    resp = [True]*21
    
    # If the returned output quantity is not a multiple of eight,
    # the remaining bits in the final data byte will be padded with zeros
    # (toward the high order end of the byte).
    
    resp.extend([False]*3)
    assert(rr.bits == resp)         # test the expected value
    
    log.debug("Write to multiple coils and read back - test 2")
    rq = client.write_coils(1, [False]*8, unit=UNIT)
    rr = client.read_coils(1, 8, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    assert(rr.bits == [False]*8)         # test the expected value
    
    log.debug("Read discrete inputs")
    rr = client.read_discrete_inputs(0, 8, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    
    log.debug("Write to a holding register and read back")
    rq = client.write_register(1, 10, unit=UNIT)
    rr = client.read_holding_registers(1, 1, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    assert(rr.registers[0] == 10)       # test the expected value
    
    log.debug("Write to multiple holding registers and read back")
    rq = client.write_registers(1, [10]*8, unit=UNIT)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    assert(rr.registers == [10]*8)      # test the expected value
    
    log.debug("Read input registers")
    rr = client.read_input_registers(1, 8, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    
    arguments = {
        'read_address':    1,
        'read_count':      8,
        'write_address':   1,
        'write_registers': [20]*8,
    }
    log.debug("Read write registeres simulataneously")
    rq = client.readwrite_registers(unit=UNIT, **arguments)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(rq.function_code < 0x80)     # test that we are not an error
    assert(rq.registers == [20]*8)      # test the expected value
    assert(rr.registers == [20]*8)      # test the expected value
    
    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()
Пример #16
0
    if args.op == 'w':
        if args.fun == 'hr':
            rq = client.write_register(args.adr, args.val, unit=args.id)
        elif args.fun == 'co':
            rq = client.write_coil(args.adr, args.val, unit=args.id)
        
        print "Write function return code : " + str(rq.function_code)
    else :
        if args.fun == 'hr':
            rr = client.read_holding_registers(args.adr, args.qty, unit=args.id)
            if rr != None: results = rr.registers
        elif args.fun == 'ri':
            rr = client.read_input_registers(args.adr, args.qty, unit=args.id)
            if rr != None: results = rr.registers
        elif args.fun == 'di':
            rr = client.read_discrete_inputs(args.adr, args.qty, unit=args.id)
            if rr != None: results = rr.bits
        elif args.fun == 'co':
            rr = client.read_coils(args.adr, args.qty, unit=args.id)
            if rr != None: results = rr.bits

        if results is not None:
            print "[SUCCESS] value:"
            print "    " + ",".join(hex(n) for n in results)
        else:
            print("[ERROR]")

    client.close()
except:
    print("Unknown Exception")
    raise
Пример #17
0
def youbot_modbus_server_service():
    global station_states, button_states, modbus_data_validity
    connection_error_count = 0
    
    rospy.init_node('youbot_modbus_server')
    
    # Grab all of the parameters from the launch file
    mb_server_ip = rospy.get_param("~modbus_server_ip")
    mb_server_port = rospy.get_param("~modbus_server_port")
    mb_station_status_topic = rospy.get_param("~station_status_topic")
    mb_button_status_topic = rospy.get_param("~button_status_topic")
    plc_polling_rate = rospy.Rate(rospy.get_param("~plc_polling_rate_hz"))
    
    # Update the array sizes
    station_states = [False] * plc_num_stations
    button_states =  [False] * (plc_num_buttons * 2)
    
    # Create two services for nodes to call and get current sensor & button states
    s = rospy.Service(mb_station_status_topic, YoubotModbusSensorMsg, handle_station_request)
    t = rospy.Service(mb_button_status_topic, YoubotModbusButtonMsg, handle_button_request)
    
    # Attempt to connect to the PLC Modbus server
    try:
        # Connect to the Modbus Server
        client = ModbusClient(mb_server_ip, mb_server_port)
        if client.connect() == False:
            raise
    # We failed to connect to the PLC Modbus server. Report error and shutdown.
    except:
        except_desc = "Could not initiate connection with Modbus server"
        rospy.logerr(except_desc)
        rospy.signal_shutdown(except_desc)
    # We suceeded, so report the connection and continue
    else:
        rospy.loginfo("Youbot Modbus service successfully connected to: " + str(mb_server_ip) + ":" + str(mb_server_port))
        rospy.loginfo("Awaiting ROS service calls...")
    
    # Main loop for polling the Modbus Server on the PLC - plc_polling_rate param is in launch file
    while not rospy.is_shutdown():
        
        # Request data from the PLC Modbus server
        try:
            # Get the current station values (every two values is a ball/done pair)
            returned_station_states = client.read_discrete_inputs(0x8000, plc_num_stations*2)
            # Get the current button values (every two values is a button/indicator pair) (buttons follow stations in PLC addresses)
            returned_button_states = client.read_discrete_inputs((0x8000+(plc_num_stations*2)), plc_num_buttons*2)
            
            # Raise an exception if the server did not respond with the message type we were expecting
            if type(returned_station_states) != bit_read_message.ReadDiscreteInputsResponse or \
               type(returned_button_states ) != bit_read_message.ReadDiscreteInputsResponse:
                raise
            
            # If the data was invalid on a previous iteration, we need to report the transition
            if modbus_data_validity == False:
                connection_error_count = 0
                modbus_data_validity = True
                rospy.loginfo("PLC communication has been restored. Data validity: " + str(modbus_data_validity))
        
        # We did not get a reply from the PLC Modbus server, so count it and report a warning message.
        except exceptions.ConnectionException:
            modbus_data_validity = False
            connection_error_count += 1
            except_desc = "PLC did not respond to data request. Data validity: " + str(modbus_data_validity)
            rospy.logwarn(except_desc)
        
        # The PLC Modbus server did not respond with the type of message we were expecting.
        except:
            except_desc = "An exception was raised while attempting to read from the Modbus server"
            rospy.logerr(except_desc)
            rospy.signal_shutdown(except_desc)
        
        # Data is GOOD, so let's process it.
        else:
            # Report to all service calls that the data is GOOD
            modbus_data_validity = True
            # We got a good response, so update the arrays
            update_sensor_array(returned_station_states, plc_num_stations)
            update_button_array(returned_button_states, plc_num_buttons)
            
        # If we have not heard back from the PLC Modbus server in 
        # (connection_error_count * (1/plc_polling_rate) seconds, so we should shutdown.
        if connection_error_count >= 10:
            except_desc = "Could not communicate with PLC. Error count exceeded: "+ str(connection_error_count) + " failures"
            rospy.logerr(except_desc)
            rospy.signal_shutdown(except_desc)
            
        # Wait until the next Modbus poll
        plc_polling_rate.sleep()
Пример #18
0
# ! You need to launch the server first !

from pymodbus.client.sync import ModbusTcpClient
import time

print "--- START"
client = ModbusTcpClient('localhost', port=5020)

client.connect()
print "Connected to modbus server"

rr = client.read_input_registers(400, 9)
print rr.registers

rr = client.read_discrete_inputs(100, 6)
print rr.bits

# Set digital IO mode - output
client.write_coil(0, False)
client.write_coil(3, False)

# Set digital IO state
client.write_coil(100, True)
client.write_coil(103, False)

time.sleep(0.1)

rr = client.read_discrete_inputs(100, 6)
print rr.bits
Пример #19
0
class Modbus_Driver(object):
    def __init__(self, config_file, config_section=None):
        # Use a config section if the config file is being shared with other
        # parts of a project.
        if (config_section==None):
            modbus_section = 'modbus'
        with open(config_file) as f:
            # use safe_load instead load for security reasons
            modbusConfig = yaml.safe_load(f)

        self.MODBUS_TYPE = modbusConfig[modbus_section]['modbus_type']
        # Check to see if unit id is a list, if it is then set flag that it is a
        # list
        self.UNIT_ID = modbusConfig[modbus_section]['UNIT_ID']
        if isinstance(self.UNIT_ID, list):
            self.UNIT_ID_LIST = self.UNIT_ID
            #Set default UNIT_ID as first UNIT_ID in list
            self.UNIT_ID = self.UNIT_ID_LIST[0]
        else:
            # Make a unit id list from the non-list definition for compatibility
            # reasons of previous configs. This also eliminates the possibility
            # of error in calling get_data_all_devices() on a config with a non
            # list definition
            self.UNIT_ID_LIST = []
            self.UNIT_ID_LIST.append(self.UNIT_ID)

        # Start logging if enabled in config
        self.LOGGING_FLAG = modbusConfig[modbus_section]['enable_logging']
        if self.LOGGING_FLAG == True:
            #Start client logging for trouble shooting
            logging.basicConfig()
            log = logging.getLogger()
            log.setLevel(logging.DEBUG)

        # Start appropriate client based on the type specified in the config
        if self.MODBUS_TYPE == 'serial':
            print('serial')
            self.METHOD = modbusConfig[modbus_section]['method']
            self.SERIAL_PORT = modbusConfig[modbus_section]['serial_port']
            self.STOPBITS = modbusConfig[modbus_section]['stopbits']
            self.BYTESIZE = modbusConfig[modbus_section]['bytesize']
            self.PARITY = modbusConfig[modbus_section]['parity']
            self.BAUDRATE = modbusConfig[modbus_section]['baudrate']
        elif self.MODBUS_TYPE == 'tcp':
            self.IP_ADDRESS = modbusConfig[modbus_section]['ip']
            self.PORT = modbusConfig[modbus_section]['tcp_port']
        else:
            print("Invalid modbus type")
            exit()

        # Set the byte order as big or little endian
        if modbusConfig[modbus_section]['byte_order'] == 'big':
            self.BYTE_ORDER = Endian.Big
        elif modbusConfig[modbus_section]['byte_order'] == 'little':
            self.BYTE_ORDER = Endian.Little
        else:
            print("invalid byte order") # change to except later
            exit()

        # Set the word order as big or little endian
        if modbusConfig[modbus_section]['word_order'] == 'big':
            print("big")
            self.WORD_ORDER = Endian.Big
        elif modbusConfig[modbus_section]['word_order'] == 'little':
            self.WORD_ORDER = Endian.Little
        else:
            print("invalid byte order") # change to except later
            exit()

        # Read in all registers specified in the YAML config
        self.coil_register_dict = modbusConfig[modbus_section]['coil_registers']
        self.discrete_register_dict = modbusConfig[modbus_section]['discrete_registers']
        self.holding_register_dict = modbusConfig[modbus_section]['holding_registers']
        self.input_register_dict = modbusConfig[modbus_section]['input_registers']

        # Apply register offset if specified
        self.OFFSET_REGISTERS = modbusConfig[modbus_section]['OFFSET_REGISTERS']
        for key in self.holding_register_dict:
            self.holding_register_dict[key][0] -= self.OFFSET_REGISTERS


    def initialize_modbus(self):
        """
        initalize correct client according to type specified in config:
            'tcp' or 'serial'
        """
        if self.MODBUS_TYPE == 'serial':
            self.client= ModbusSerialClient(method = self.METHOD, port=self.SERIAL_PORT,stopbits = self.STOPBITS, bytesize = self.BYTESIZE, parity = self.PARITY, baudrate= self.BAUDRATE)
            connection = self.client.connect()

        if self.MODBUS_TYPE == 'tcp':
            self.client = ModbusTcpClient(self.IP_ADDRESS,port=self.PORT)



    def write_single_register(self,register,value, unit=None):
        """
        :param register: address of reigster to write
        :param value: Unsigned short
        :returns: Status of write
        """
        if (unit is None):
            unit = self.UNIT_ID
        response = self.client.write_register(register,value,unit)
        return response

    def write_register(self,register_name,value, unit=None):
        """
        :param register_name: register key from holding register dictionary
            generated by yaml config
        :param value: value to write to register
        :returns: -- Nothing
        """
        if (unit is None):
            unit = self.UNIT_ID

        builder = BinaryPayloadBuilder(byteorder=self.BYTE_ORDER,
            wordorder=self.WORD_ORDER)
        if (self.holding_register_dict[register_name][1] == '8int'):
            builder.add_8bit_int(value)
        elif (self.holding_register_dict[register_name][1] == '8uint'):
            builder.add_8bit_uint(value)
        elif (self.holding_register_dict[register_name][1] == '16int'):
            builder.add_16bit_int(value)
        elif (self.holding_register_dict[register_name][1] == '16uint'):
            builder.add_16bit_uint(value)
        elif (self.holding_register_dict[register_name][1] == '32int'):
            builder.add_32bit_int(value)
        elif (self.holding_register_dict[register_name][1] == '32uint'):
            builder.add_32bit_uint(value)
        elif (self.holding_register_dict[register_name][1] == '32float'):
            builder.add_32bit_float(value)
        elif (self.holding_register_dict[register_name][1] == '64int'):
            builder.add_64bit_int(value)
        elif (self.holding_register_dict[register_name][1] == '64uint'):
            builder.add_64bit_uint(value)
        elif (self.holding_register_dict[register_name][1] == '64float'):
            builder.add_64bit_float(value)
        else:
            print("Bad type")
            exit()
        payload = builder.build()
        self.client.write_registers(self.holding_register_dict[register_name][0], payload, skip_encode=True, unit = self.UNIT_ID)

    def write_coil(self,register,value, unit=None):
        """
        :param register_name: register key from holding register dictionary
            generated by yaml config
        :param value: value to write to register
        :returns:
        """
        if (unit is None):
            unit = self.UNIT_ID

        response = self.client.write_coil(register,value,unit)
        return response

    def read_coil(self,register, unit=None):
        """
        :param register: coil register address to read
        :returns: value stored in coil register
        """
        if (unit is None):
            unit = self.UNIT_ID

        rr = self.client.read_coils(register, 1, unit=unit)
        return rr.bits[0]

    def read_discrete(self,register,unit=None):
        """
        :param register: discrete register address to read
        :returns: value stored in coil register
        """
        if (unit is None):
            unit = self.UNIT_ID

        rr = self.client.read_discrete_inputs(register, count=1,unit=unit)
        return rr.bits[0]

    def read_register_raw(self,register,length, unit=None):
        """
        :param register: base holding register address to read
        :param length: amount of registers to read to encompass all of the data necessary
            for the type
        :returns: A deferred response handle
        """
        if (unit is None):
            unit = self.UNIT_ID

        response = self.client.read_holding_registers(register,length,unit= self.UNIT_ID)
        return response

    def read_input_raw(self,register,length, unit=None):
        """
        :param register: base input register address to read
        :param length: amount of registers to read to encompass all of the data necessary
            for the type
        :returns: A deferred response handle
        """
        if (unit is None):
            unit = self.UNIT_ID

        response = self.client.read_input_registers(register,length,unit= self.UNIT_ID)
        return response
    #TODO ADD unit id here! and to decode input register
    def decode_register(self,register,type, unit=None):
        """
        :param register: holding register address to retrieve
        :param type: type to interpret the registers retrieved as
        :returns: data in the type specified

        Based on the type provided, this function retrieves the values contained
        in the register address specfied plus the amount necessary to encompass
        the the type. For example, if 32int is specified with an address of 200
        the registers accessed would be 200 and 201.

        The types accepted are listed in the table below along with their length
        |   Type          | Length (registers) |
        | ------------- |:------------------:|
        |        ignore |                  1 |
        |          8int |                  1 |
        |         8uint |                  1 |
        |         16int |                  1 |
        |        16uint |                  1 |
        |         32int |                  2 |
        |        32uint |                  2 |
        |       32float |                  2 |
        |         64int |                  4 |
        |        64uint |                  4 |
        |       64float |                  4 |
        """
        if (unit is None):
            unit = self.UNIT_ID
        #omitting string for now since it requires a specified length
        if type == '8int':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_8bit_int()

        elif type == '8uint':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_8bit_uint()
        elif type == '16int':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_16bit_int()
        elif type == '16uint':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_16bit_uint()
        elif type == '32int':
            rr = self.read_register_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_int()
        elif type == '32uint':
            rr = self.read_register_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_uint()
        elif type == '32float':
            rr = self.read_register_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_float()
        elif type == '64int':
            rr = self.read_register_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_int()
        elif type == '64uint':
            rr = self.read_register_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_uint()
        elif type == 'ignore':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.skip_bytes(8)
        elif type == '64float':
            rr = self.read_register_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_float()
        else:
            print("Wrong type specified")
            exit()

        return output

    def decode_input_register(self,register,type, unit=None):
        """
        :param register: input register address to retrieve
        :param type: type to interpret the registers retrieved as
        :returns: data in the type specified

        Based on the type provided, this function retrieves the values contained
        in the register address specfied plus the amount necessary to encompass
        the the type. For example, if 32int is specified with an address of 200
        the registers accessed would be 200 and 201.

        The types accepted are listed in the table below along with their length
        |   Type          | Length (registers) |
        | ------------- |:------------------:|
        |        ignore |                  1 |
        |          8int |                  1 |
        |         8uint |                  1 |
        |         16int |                  1 |
        |        16uint |                  1 |
        |         32int |                  2 |
        |        32uint |                  2 |
        |       32float |                  2 |
        |         64int |                  4 |
        |        64uint |                  4 |
        |       64float |                  4 |
        """
        if (unit is None):
            unit = self.UNIT_ID
        #omitting string for now since it requires a specified length
        if type == '8int':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_8bit_int()

        elif type == '8uint':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_8bit_uint()
        elif type == '16int':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_16bit_int()
        elif type == '16uint':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_16bit_uint()
        elif type == '32int':
            rr = self.read_input_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_int()
        elif type == '32uint':
            rr = self.read_input_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_uint()
        elif type == '32float':
            rr = self.read_input_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_float()
        elif type == '64int':
            rr = self.read_input_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_int()
        elif type == '64uint':
            rr = self.read_input_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_uint()
        elif type == 'ignore':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.skip_bytes(8)
        elif type == '64float':
            rr = self.read_input_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER,
                    wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_float()
        else:
            print("Wrong type specified")
            exit()

        return output


    def get_data(self,unit=None):
        """
        :returns: Dictionary containing the value retrieved for each register
        contained in the YAML config file, register names cannot be repeated
        or the register will be overwritten
        """
        if unit is None:
            unit = self.UNIT_ID
        output = {}
        for key in self.coil_register_dict:
            #print(key)
            output[key] = self.read_coil(self.coil_register_dict[key][0],unit)

        for key in self.discrete_register_dict:
            #print(key)
            output[key] = self.read_discrete(self.discrete_register_dict[key][0],unit)

        for key in self.holding_register_dict:
            #print(key)
            output[key] = self.decode_register(self.holding_register_dict[key][0],self.holding_register_dict[key][1],unit)

        for key in self.input_register_dict:
            #print(key)
            output[key] = self.decode_input_register(self.input_register_dict[key][0],self.input_register_dict[key][1],unit)

        return output
    def get_data_all_devices(self):
        reg_data_dict = {}
        cnt = 1
        for dev_id in self.UNIT_ID_LIST:
            new_key = str(self.UNIT_ID_LIST[dev_id])
            if str(self.UNIT_ID_LIST[dev_id]) in reg_data_dict:
                new_key = new_key + '_' + str(cnt)
                cnt += 1
            reg_data_dict[new_key] = self.get_data(self.UNIT_ID_LIST[dev_id])
        return reg_data_dict
    def kill_modbus(self):
        """
        Closes connection with Modbus Slave
        """
        self.client.close()
class clientthreads(threading.Thread):

    def __init__(self, vnic, ipaddr, port):
        threading.Thread.__init__(self)
        self.ipaddr = ipaddr  # ip address
        self.port = port  # port address
        self.vnic = vnic  # virtual nic
        self.mode = ""  # server or client
        self.state = ""  # up or down
        self.dest = ""  # destination address for client
        self.clientstop = threading.Event()
        self.server = ""
        self.client = ""
        self.framer = ""
        self.vnicm = ""
        self.runtime= 0
        self.delayr = random.uniform(0,5)
        self.delayw = random.uniform(0,60)
        self.firstdelay = 0
        self.pstart= ""


    def run(self):
        self.client = ModbusTcpClient(self.dest, self.port, source_address=(self.ipaddr, 0), retries=1, retry_on_empty=True)
        if(self.mode=="read"):
            self.clientintr()
        elif(self.mode=="write"):
            self.clientintw()
        else:
            print "wrong mode specified"

    def clientintr(self):  # instantiate server stuff
        while(not self.clientstop.is_set()):
            if(time.time() - self.pstart > self.runtime):
                print "stopping"
                break
            if(self.firstdelay < 1):
                print "Start RDelay is: " + str(self.delayr)
                time.sleep(self.delayr)
                self.firstdelay = 1
                print "Starting Reads"

            self.clientreads()
            print "\n\r-----read-----\n\r"
            print self.dest 
            print time.time() - self.pstart
            print "------------------\n\r"
    
    def clientintw(self):  # instantiate server stuff
        while(not self.clientstop.is_set()):
            if(time.time() - self.pstart > self.runtime):
                print "stopping"
                break
            if(self.firstdelay < 1):
                print "Start WDelay is: " + str(self.delayw)
                time.sleep(self.delayw)
                self.firstdelay = 1
                print "Starting Writes"

            self.clientwrites()
            print "\n\r-----write----\n\r"
            print self.dest 
            print time.time() - self.pstart
            print "------------------\n\r"


    def clientreads(self):
        self.client.read_coils(1, 10)
        self.client.read_discrete_inputs(1, 10)
        self.client.read_holding_registers(1, 10)
        self.client.read_input_registers(1, 10)
        time.sleep(5)

    def clientwrites(self):
        self.client.write_coil(1, True)
        self.client.write_register(1, 3)
        self.client.write_coils(1, [True]*10)
        self.client.write_registers(1, [3]*10)
        time.sleep(60)
    
    def alloc(self):  # Allocate ip address
        if (validateIP(self.ipaddr, self.vnicm)):
            cmdargs = [self.vnic, self.ipaddr]
            subprocess.call(["ifconfig"] + cmdargs)
        else:
            return 0

    def dealloc(self):  # De-allocate ip address
        cmdargs = [self.vnic]
        subprocess.call(["ifconfig"] + cmdargs + ["down"])

    def stop(self):
        self.clientstop.set()
        return
Пример #21
0
#!/usr/bin/env python3

#from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.client.sync import ModbusTcpClient

client = ModbusTcpClient('127.0.0.1', port=5020)
client.connect()

di = client.read_discrete_inputs(address=0x000, count=8)
co = client.read_coils(address=0x100, count=8)
hr = client.read_holding_registers(address=0x200, count=4)
ir = client.read_input_registers(address=0x300, count=1)

print(di.bits)

print(co.bits)

#print(hr.registers)
decoder = BinaryPayloadDecoder.fromRegisters(hr.registers)
decoded_string = decoder.decode_string(8)
print(decoded_string)

#print(ir.registers)
decoder = BinaryPayloadDecoder.fromRegisters(ir.registers)
decoded_8bit_int = decoder.decode_8bit_int()
print(decoded_8bit_int)
Пример #22
0
                clientTCP.close()
                times()
            else:
                a = 0

        elif function_code == '02':
            clientTCP = ModbusTcpClient(AddrTCP)
            connection = clientTCP.connect()
            #print(clientTCP.timeout)
            if connection == True:
                times()
                print(
                    '--------------------------------------------------FC02----------------------------------------------------------'
                )
                Request = clientTCP.read_discrete_inputs(0x00C4,
                                                         0x0016,
                                                         unit=0x11)
                resp = reversePacket('FC02', Request)
                print('')
                print(
                    '*********************************************************'
                )
                print('Resultado comparado com Modbus RTU:')
                print(PacketCompare('FC02', sglobal, resp))
                print('')
                print('Resposta do Modbus TCP:')
                print(Request)
                print('')
                print('Valor do Modbus TCP: ' + resp)
                print(
                    '*********************************************************'
Пример #23
0
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setWindowTitle("PLC Timing Charts")

        self.main_widget = QtWidgets.QWidget(self)
        self.setCentralWidget(self.main_widget)

        # Create the maptlotlib FigureCanvas object,
        # which defines a single set of axes as self.axes.
        self.left_in = MplCanvas(self)
        # self.left_out = MplCanvas(self)
        # self.right_in = MplCanvas(self)
        # self.right_out = MplCanvas(self)

        self.plc_client = ModbusTcpClient("10.24.0.2")
        self.left_in.fkth_sensor.add = 0x400
        self.left_in.fkth_purger.add = 0x401
        self.left_in.tr_sensor.add = 0x402
        self.left_in.tr_purger.add = 0x403

        self.timing_layout = QtWidgets.QGridLayout(self.main_widget)
        self.timing_layout.addWidget(self.left_in, *(0, 0))
        # self.timing_layout.addWidget(self.left_out, *(0, 1))
        # self.timing_layout.addWidget(self.right_in, *(1, 0))
        # self.timing_layout.addWidget(self.right_out, *(1, 1))

        n_samples = np.linspace(0, 499, 100)
        for _side in [self.left_in]:  # , self.left_out, self.right_in, self.right_out]:
            for _plot in [
                _side.fkth_sensor,
                _side.fkth_purger,
                _side.tr_sensor,
                _side.tr_purger,
            ]:
                _plot.xdata = [(n_samples[i]) for i in range(len(n_samples))]
                _plot.ydata = [(0) for i in range(len(n_samples))]
                _plot.plot_ref = None
        self.update_plot()
        self.showMaximized()

        # dataAcquire = threading.Thread(name="data loop", target=self.acquire_signal)
        # dataAcquire.start()
        # Setup a timer to trigger the redraw by calling update_plot.

        acquire = threading.Thread(target=self.acquire_signal, daemon=True)
        # plotting = threading.Thread(target=self.update_plot, daemon=True)

        acquire.start()
        # plotting.start()
        # acquire.join()
        # plotting.join()
        self.timer = QtCore.QTimer()
        self.timer.setInterval(25)
        # self.timer.timeout.connect(self.acquire_signal)
        self.timer.timeout.connect(self.update_plot)
        self.timer.start()

    def acquire_signal(self):
        while True:
            start = time.time()
            for _side in [
                self.left_in
            ]:  # , self.left_out, self.right_in, self.right_out]:
                for _plot in [
                    _side.fkth_sensor,
                    _side.fkth_purger,
                    _side.tr_sensor,
                    _side.tr_purger,
                ]:
                    _plot.response = int(
                        (self.plc_client.read_discrete_inputs(_plot.add)).bits[0]
                        == True
                    )
                    _plot.ydata = _plot.ydata[1:] + [_plot.response]
            elapsed_time = time.time() - start
            print(elapsed_time)

    def update_plot(self):

        # Drop off the first y element, append a new one.
        for _side in [self.left_in]:  # , self.left_out, self.right_in, self.right_out]:
            # for _plot in [
            #     _side.fkth_sensor,
            #     _side.fkth_purger,
            #     _side.tr_sensor,
            #     _side.tr_purger,
            # ]:
            # _plot.response = int(
            #     (self.plc_client.read_discrete_inputs(_plot.add)).bits[0] == True
            # )

            # Note: we no longer need to clear the axis.
            # First time we have no plot reference, so do a normal plot.
            # .plot returns a list of line <reference>s, as we're
            # only getting one we can take the first element.
            # Then once we have a reference, we can use it to update the data for that line.
            if _side.fkth_sensor.plot_ref is None:
                _side.fkth_sensor.plot_refs = _side.fkth_sensor.plot(
                    _side.fkth_sensor.xdata,
                    _side.fkth_sensor.ydata,
                    "b",
                    drawstyle="steps-mid",
                )
                _side.fkth_sensor.plot_ref = _side.fkth_sensor.plot_refs[0]
            else:

                _side.fkth_sensor.plot_ref.set_ydata(_side.fkth_sensor.ydata)

            if _side.fkth_purger.plot_ref is None:
                _side.fkth_purger.plot_refs = _side.fkth_purger.plot(
                    _side.fkth_purger.xdata,
                    _side.fkth_purger.ydata,
                    "r",
                    drawstyle="steps-mid",
                )
                _side.fkth_purger.plot_ref = _side.fkth_purger.plot_refs[0]
            else:

                _side.fkth_purger.plot_ref.set_ydata(_side.fkth_purger.ydata)

            if _side.tr_sensor.plot_ref is None:
                _side.tr_sensor.plot_refs = _side.tr_sensor.plot(
                    _side.tr_sensor.xdata,
                    _side.tr_sensor.ydata,
                    "c",
                    drawstyle="steps-mid",
                )
                _side.tr_sensor.plot_ref = _side.tr_sensor.plot_refs[0]
            else:

                _side.tr_sensor.plot_ref.set_ydata(_side.tr_sensor.ydata)

            if _side.tr_purger.plot_ref is None:
                _side.tr_purger.plot_refs = _side.tr_purger.plot(
                    _side.tr_purger.xdata,
                    _side.tr_purger.ydata,
                    "m",
                    drawstyle="steps-mid",
                )
                _side.tr_purger.plot_ref = _side.tr_purger.plot_refs[0]
            else:

                _side.tr_purger.plot_ref.set_ydata(_side.tr_purger.ydata)
            # Trigger the canvas to update and redraw.
            _side.draw()
Пример #24
0
class ModbusTCPPlcConnector:
    """
    Instantiates the connection to a PLC via modbus/TCP.
    """
    def __init__(self, plc_ip_address, timeout=0):
        """
        :param plc_ip_address: The IP address of the PLC.
        """
        self.modbus_client = ModbusTcpClient(plc_ip_address, timeout=timeout)
        self.modbus_client.connect()

        # Map of motor controls to modbus/TCP bits.
        self.motor_controls = {
            "control-motor-up": int(ModbusTCPRegisters.ControlMotorUp),
            "control-motor-down": int(ModbusTCPRegisters.ControlMotorDown),
            "control-motor-left": int(ModbusTCPRegisters.ControlMotorLeft),
            "control-motor-right": int(ModbusTCPRegisters.ControlMotorRight)
        }
        # The proper names for the motor controls.
        self.motor_names = ["motorUp", "motorDown", "motorLeft", "motorRight"]

        # The proper names for the sensors.
        self.sensor_names = [
            "topSensor", "bottomSensor", "leftSensor", "rightSensor"
        ]

    def is_connected(self):
        """
        Is the client connected?
        :return: True is modbus client is connected
        """
        return self.modbus_client.is_socket_open()

    def get_values(self):
        """
        This function queries the state of the sensors and motor controls.
        :return: A dictionary of the state of the motor controls and the state of the sensors.
        """

        # Should the HMI not be connected to the PLC return all values as false so that while being in the disconnected
        # state, all sensors and motors are shown as off
        sensors = dict(
            zip(self.sensor_names, ["true"] * len(self.sensor_names)))
        motors = dict(zip(self.motor_names, ["true"] * len(self.motor_names)))

        if self.is_connected():

            try:
                # Read the four bits of motor state from the PLC over modbus/TCP.
                motor_values = self.modbus_client.read_coils(
                    int(ModbusTCPRegisters.PLCInputs), 4).bits[:4]

                # Read the four bits of sensors state from the PLC over modbus/TCP.
                sensor_values = self.modbus_client.read_discrete_inputs(
                    int(ModbusTCPRegisters.PLCInputs)).bits[:4]

                # Separate the limit switches of the punching arm from the light switches
                limit_switches = sensor_values[:2]

                # Separate the light switches from the limit switches of the punching arm.
                light_sensors = sensor_values[2:4]

                # The values of the motor manual values must be inverted to fit our logic.
                # The values are converted to strings.
                corrected_motor_values = [
                    str(not value).lower() for value in motor_values
                ]

                # The values are converted to strings.
                light_sensor_values = [
                    str(value).lower() for value in light_sensors
                ]

                # The values are converted to strings.
                limit_switch_values = [
                    str(value).lower() for value in limit_switches
                ]

                # Join the sensor values again.
                joined_sensor_values = limit_switch_values + light_sensor_values

                # Join the proper sensor names as keys with the corresponding sensor values into a dictionary.
                sensors = dict(zip(self.sensor_names, joined_sensor_values))

                # Join the proper motor manual names as keys with the corresponding motor manual values into a dictionary.
                motors = dict(zip(self.motor_names, corrected_motor_values))
            except:
                pass

        # Return the dictionary that contains the current motor manual values as well as sensor values.
        return {**sensors, **motors}

    def set_order(self, count):
        """
        Set an positive numeric value as amount of times the process is to be executed.
        :param count: Positive integer.
        :return: The PLC connectors response, so it can be use if of interest.
        """
        if self.is_connected():
            try:
                self.modbus_client.write_register(
                    int(ModbusTCPRegisters.Orders), count)
            except:
                pass

    def set_application_state(self, state):
        """
        Set the current application state.
        :param state:
        :return: The PLC connectors response, so it can be use if of interest.
        """
        state_value = application.Disconnected().modbus_value
        if self.is_connected():
            try:
                state_value = self.modbus_client.write_register(
                    int(ModbusTCPRegisters.HmiApplicationState),
                    state.modbus_value)
            except:
                pass
        return state_value

    def set_motor(self, motor, motor_state):
        """
        Turn a motor of the process manually on or off.
        :param motor: Which motor is to be set.
        :param motor_state: On or Off.
        :return: The PLC connectors response, so it can be use if of interest.
        """
        register = self.motor_controls[motor]
        state_value = application.Disconnected().modbus_value
        if self.is_connected():
            try:
                state_value = self.modbus_client.write_register(
                    register, int(motor_state))
            except:
                pass
        return state_value

    def set_reset(self):
        """
        Initiate the reset signal to get the PLC out of the emergency stop state.
        :return: The PLC connectors response, so it can be use if of interest.
        """
        state_value = application.Disconnected().modbus_value
        if self.is_connected():
            try:
                state_value = self.modbus_client.write_register(
                    int(ModbusTCPRegisters.Reset), 1)
            except:
                pass
        return state_value

    def get_orders(self):
        """
        Retrieve the amount of currently placed orders.
        :return: The order count.
        """
        state_value = application.Disconnected().modbus_value
        if self.is_connected():
            try:
                state_value = self.modbus_client.read_holding_registers(
                    int(ModbusTCPRegisters.Orders), 1).registers[0]
            except:
                pass
        return state_value

    def get_process_state(self):
        """
        Query the process state.
        :return: A dictionary containing the current process state.
        """
        state_value = process.PendingState().modbus_value
        if self.is_connected():
            try:
                state_value = \
                    self.modbus_client.read_holding_registers(int(ModbusTCPRegisters.ProcessState), 2).registers[0]
            except:
                pass
        return state_value

    def get_application_state(self):
        """
        Query the application state.
        :return: A dictionary containing the current application state.
        """
        state_value = application.Disconnected().modbus_value
        if self.is_connected():
            try:
                state_value = \
                    self.modbus_client.read_holding_registers(int(ModbusTCPRegisters.PlcApplicationState), 1).registers[
                        0]
            except:
                pass
        return state_value
Пример #25
0
#res = client.write_registers(0,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],unit=1)

for i, j in enumerate("001001001100"):
    client.write_coil(886 + i, int(j), unit=junction)

#for i in range(880,890):
# print(i)
# client.write_coil(i,1,unit=junction)
# time.sleep(5)

hold_reg = client.read_holding_registers(0, 99, unit=junction)
print("Holding Register:", ''.join([chr(x) for x in (hold_reg.registers)]))
print(hold_reg.registers)

input_reg = client.read_input_registers(0, 99, unit=junction)
print("Input Register:", input_reg.registers)

discrete_inputs = client.read_discrete_inputs(0, 99, unit=junction)
print("Discrete Input:", discrete_inputs.bits)

coils = client.read_coils(0, 100, unit=junction)
print("Coils:", [int(x) for x in coils.bits])

client.close()

#Junction 1 starts at coil 571     we want 001001001100
#Junction 2 starts at coil 1920 we want 100001001001
#Junction 4 starts at coil 1266 we want 001001001100
#Junction 6 starts at coil 886    we want 001001001100
Пример #26
0
# If the returned output quantity is not a multiple of eight,
# the remaining bits in the final data byte will be padded with zeros
# (toward the high order end of the byte).

resp.extend([False]*3)
assert(rr.bits == resp)         # test the expected value

log.debug("Write to multiple coils and read back - test 2")
rq = client.write_coils(1, [False]*8, unit=1)
rr = client.read_coils(1, 8, unit=1)
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.bits == [False]*8)         # test the expected value


log.debug("Read discrete inputs")
rr = client.read_discrete_inputs(0, 8, unit=1)
assert(rq.function_code < 0x80)     # test that we are not an error

log.debug("Write to a holding register and read back")
rq = client.write_register(1, 10, unit=1)
rr = client.read_holding_registers(1, 1, unit=1)
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.registers[0] == 10)       # test the expected value

log.debug("Write to multiple holding registers and read back")
rq = client.write_registers(1, [10]*8, unit=1)
rr = client.read_holding_registers(1, 8, unit=1)
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.registers == [10]*8)      # test the expected value

log.debug("Read input registers")
Пример #27
0
class PLC():
	timeSpan=0
	connected=False
	prev_res=0
	def __init__(self, ip):
		#ip should be 10.3.0.2
		self.client = ModbusTcpClient(ip)
		self.connected = self.client.connect()
		self.clearFlags()
		#self.setDefaultPurgingTime()
	def changeIP(self, ip):
		if self.connected:
			self.client.close()
			print("Modbus TCP connection closed")
		self.client = ModbusTcpClient(ip)
		self.connected = self.client.connect()
		if self.connected:
			self.clearFlags()
		return self.connected

	def clearFlags(self):
		if self.connected:
			self.client.write_coils(GLOVE_PRESENT_ADDR, (0,0,0,0,0,0,0,0,0)) #Clear all flags
			self.client.write_register(FURS_ON_TIME,5)#half second


	def waitNextGloveFlicker(self):
		if self.connected:
			for i in range(50):
				result = self.client.read_discrete_inputs(GLOVE_PRESENT_ADDR,1)
				if(self.prev_res==0 and result.bits[0]>0): #Check for rising edge
					self.prev_res=result.registers[0]
					return 1
				self.prev_res=result.registers[0]
				time.sleep(0.02)
			print("Production Line Stopped")
			return 0
		print("No PLC Connection")
		time.sleep(0.5)
		#Do not wait next glove if no connection, return -1
		return -1

	def waitNextGlove(self):
		if self.connected:
			for i in range(500):
				if not self.connected:
					break
				try:
					result = self.client.read_discrete_inputs(GLOVE_PRESENT_ADDR,1)
					if result.bits[0]:
						self.client.write_coil(GLOVE_PRESENT_ADDR, False)
						time.sleep(0.03) ##Displacement delay
						return 1
					time.sleep(0.002)
				except:
					print("Changing PLC IP Address")
			print("Production Line Stopped")
			return 0
		time.sleep(1)
		print("No PLC Connection")
		#Do not wait next glove if no connection, return 0
		return -1
	def readSensors(self):
		if self.connected:
			try:
				result = self.client.read_discrete_inputs(GLOVE_PRESENT_ADDR,4)
				for side, bit in enumerate(result.bits):
					if bit:
						self.client.write_coil(GLOVE_PRESENT_ADDR+side, False)
				return result.bits
			except:
				print("Changing PLC IP Address")
		print("No PLC Connection")
		#Do not wait next glove if no connection, return 0
		return -1

	def purgeGlove32(self, line):
		if self.connected:
			#activate purger by setting M1, will be cleared by PLC
			self.client.write_register(PURGER_ADDR+line, 1)
			time.sleep(0.5)
			self.client.write_register(PURGER_ADDR+line, 0)

	def purgeGlove(self, line):
		if self.connected:
			#activate purger by setting M1, will be cleared by PLC
			self.client.write_coil(PURGER_ADDR+line, True)

	def setPurgeDelay_100ms(self,line,val):
		if self.connected:
			self.client.write_register(PURGE_DELAY_ADDR+line,val)

	def setPurgeDuration_100ms(self,line,val):
		if self.connected:
			self.client.write_register(PURGING_DURATION_ADDR+line,val)

	def setPurgeInterval_100ms(self,line,val):
		if self.connected:
			self.client.write_register(PURGE_INTERVAL_ADDR+line,val)

	def setDefaultPurgingTime(self):
		if self.connected:
			for i in range(4):
				self.setPurgeDuration_100ms(i,8)
				self.setPurgeInterval_100ms(i,3)

	def isFormerAnchor(self):
		return self.readNClearFlag(FORMER_ANCHOR_ADDR) #Former Anchor Flag M11

	def readRasmAnchor(self,side):
		return self.readNClearFlag(RASM_ANCHOR_ADDR+side) #RASM Anchor Flag M4~M7

	def readNClearFlag(self, addr):
		if self.connected:
			try:
				result = self.client.read_discrete_inputs(addr,1)
				if result.bits[0]:
					self.client.write_coil(addr, False)
					return 1	#read and cleared
				else:
					return 0	#no flag
			except AttributeError:
				print("Anchor Checking no reading because lost PLC connection")
				return -1
		else:
			return -1	#no connection

	def setDualBinFlap(self,side,val):
		if self.connected:
			if val:
				self.client.write_coil(DUAL_BIN_FLAP_ON+side, True)
			else:
				self.client.write_coil(DUAL_BIN_FLAP_OFF+side, True)

	def setFlipDuration_100ms(self,val):
		if self.connected:
			self.client.write_register(FLIP_DURATION_ADDR,val)

	def activateFurs(self,side):
		if self.connected:
			self.client.write_coil(FURS_ADDR+side, True)


	def close(self):
		self.client.close()
		print("Modbus TCP connection closed")
Пример #28
0
        if args.type == 'HR':
            hr_read = client.read_holding_registers(args.offset,
                count=args.count)
            assert(hr_read.function_code < 0x80)
            print(hr_read.registers[0:args.count])

        # NOTE: read_holding_registers
        elif args.type == 'IR':
            ir_read = client.read_input_registers(args.offset,
                count=args.count)
            assert(ir_read.function_code < 0x80)
            print(ir_read.registers[0:args.count])

        # NOTE: read_discrete_inputs
        elif args.type == 'DI':
            di_read = client.read_discrete_inputs(args.offset,
                count=args.count)
            assert(di_read.function_code < 0x80)
            print(di_read.bits)

        # NOTE: read_discrete_inputs
        elif args.type == 'CO':
            co_read = client.read_coils(args.offset,
                count=args.count)
            assert(co_read.function_code < 0x80)
            print(co_read.bits)



    client.close()
Пример #29
0
from time import sleep

from pymodbus.client.sync import ModbusTcpClient

inputState = [False] * 32
outputState = [False] * 32

clientDI_1 = ModbusTcpClient('192.168.82.77')
clientDO_1 = ModbusTcpClient('192.168.82.76')

clientDO_1.write_coils(1, inputState)

while not sleep(0.05):
    try:
        result = clientDI_1.read_discrete_inputs(1, 32)
        activeButtonsIndexes = [i for i, x in enumerate(result.bits) if x]
        for index in activeButtonsIndexes:
            if inputState[index] != result.bits[index]:
                print(f"Button pressed {index}")
                outputState[index] = not outputState[index]
        inputState = result.bits
        clientDO_1.write_coils(1, outputState)
        clientDI_1.close()
        clientDO_1.close()
    except:
        print("error, resetting")
Пример #30
0
def acquire_signal(data_io1, data_io2, data_io3, data_io4, n_samples):
    io_1 = IO()
    io_2 = IO()
    io_3 = IO()
    io_4 = IO()

    io_1.ydata = [(0) for i in range(len(n_samples))]
    io_2.ydata = [(0) for i in range(len(n_samples))]
    io_3.ydata = [(0) for i in range(len(n_samples))]
    io_4.ydata = [(0) for i in range(len(n_samples))]

    try:
        with open("./plc.json") as f:
            plc = json.load(f)
            ip = plc["ipAddress"]
            io_1.typ, io_1.bit = get_bit(plc["Ports"]["IOport1"])
            io_2.typ, io_2.bit = get_bit(plc["Ports"]["IOport2"])
            io_3.typ, io_3.bit = get_bit(plc["Ports"]["IOport3"])
            io_4.typ, io_4.bit = get_bit(plc["Ports"]["IOport4"])
            plc_client = ModbusTcpClient(ip)
        while True:
            start = time.time()
            input_data = plc_client.read_discrete_inputs(1024, 32)
            output_data = plc_client.read_discrete_inputs(1280, 32)

            for _io in [io_1, io_2, io_3, io_4]:
                if _io.typ == "X":
                    _io.response = int(input_data.bits[_io.bit] == True)
                elif _io.typ == "Y":
                    _io.response = int(output_data.bits[_io.bit] == True)
                else:
                    io_1.response = -2

                _io.ydata = _io.ydata[1:] + [_io.response]
                _io.log_val = str(f"{_io.typ}{_io.bit}:{_io.response}")

            data_io1.send(io_1.ydata)
            data_io2.send(io_2.ydata)
            data_io3.send(io_3.ydata)
            data_io4.send(io_4.ydata)

            elapsed_time = time.time() - start
            remaining_time = 0.05 - elapsed_time
            err = "No error"
            if remaining_time > 0:
                time.sleep(remaining_time)
            else:
                err = "Warning: Acquisition rate is above 50ms"
                print(err)
            msg = str(f"Current acquisition rate is: {elapsed_time}seconds")
            logger(
                [
                    datetime.datetime.now().strftime("%H:%M:%S.%f"),
                    msg,
                    err,
                    io_1.log_val,
                    io_2.log_val,
                    io_3.log_val,
                    io_4.log_val,
                ]
            )

    except:
        err = f"Unable to connect to PLC. Please confirm if PLC address is {ip}"
        logger(
            [datetime.datetime.now().strftime("%H:%M:%S.%f"), "inf", err, 0, 0, 0, 0]
        )
        print(err)
Пример #31
0
class ModbusTCP(SmartPlugin):
    ALLOW_MULTIINSTANCE = False
    PLUGIN_VERSION = "1.0.0"

    ####################################################################################################
    #
    #
    #
    #
    #
    ####################################################################################################
    def __init__(self,
                 smarthome,
                 host,
                 timeout=10,
                 port=502,
                 cycle=5,
                 byteorder='big',
                 wordorder='little'):
        ##Initialdaten aus Plugin.conf
        self._sh = smarthome
        self._items = {}
        self.timeout = float(timeout)
        self._device = str(host)
        self.port = int(port)
        self.cycle = int(cycle)
        self._unit = 0x1
        self.logger = logging.getLogger(__name__)
        ######################################
        self._adresses = []
        self.fail = False
        #1: 	bool						0...1
        #5: 	8-bit signed value			0...255
        #5.001: 8-bit unsigned value		0...100
        #6: 	8-bit signed value			-128...127
        #7: 	16-bit unsigned value		0...65535
        #8: 	16-bit signed value			-32768...32767
        #9: 	floating point 				-671088,64 - 670760,96
        if byteorder == 'big':
            self.byteorder = Endian.Big
        else:
            self.byteorder = Endian.Little
        if wordorder == 'big':
            self.wordorder = Endian.Big
        else:
            self.wordorder = Endian.Little

        if cycle:
            self._sh.scheduler.add('ModbusTCP: read cycle',
                                   self._read,
                                   prio=5,
                                   cycle=self.cycle)

        self.connect()
        self._lock = threading.Lock()

    def run(self):  ##plugin starten
        self.alive = True

    def stop(self):  ##plugin stoppen
        self.alive = False
        #self.client.disconnect()
        self.client.close()
        self.logger.info('ModbusTCP: Stopped!')

    def parse_logic(self, logic):  ##nicht benoetigt
        pass

    def connect(self):

        try:
            #if self.device is not None:
            self.client = ModbusClient(self._device, self.port)
            #self.client.connect()
            #self.connected = True
            self.logger.info('ModbusTCP: Connected to {0}'.format(
                self._device))
            self.fail = False
        except Exception as e:
            if self.fail == False:
                self.logger.error(
                    'ModbusTCP: Could not connect to : {0}, {1]'.format(
                        self._device, e))
            self.fail = True
####################################################################################################
#Items beim start überprüfen, auf modbus_on = 1
####################################################################################################

    def parse_item(self, item):
        if self.has_iattr(item.conf, 'modbus_function'):
            mfunction = item.conf['modbus_function']
            #1 Read Coil Status         1bit
            #2 Read Input Status        16bit
            #3 Read Holding Registers   16bit
            #4 Read Input Registers     16bit
            #5 Force Single Coil        1bit
            #6 Preset Single Register   16bit
            if mfunction not in ['1', '2', '3', '4', '5', '6']:
                self.logger.warning(
                    "ModbusTCP: This is not a valid Modbus function.{0} {1}.".
                    format(item, mfunction))
                pass

            if self.has_iattr(item.conf, 'modbus_read'):
                madress = item.conf['modbus_read']
                self.logger.debug(
                    "ModbusTCP: {0} - read from {2} and mfunction {1}".format(
                        item, mfunction, madress))
                self._adresses.append({
                    'mfunction': int(mfunction),
                    'madress': int(madress),
                    'item': item
                })
                return self.update_item

            if self.has_iattr(item.conf, 'modbus_write'):
                madress = item.conf['modbus_write']
                mfunction = item.conf['modbus_function']
                self.logger.debug(
                    "ModbusTCP: {0} - write to {1} and mfunction{2}".format(
                        item, madress, mfunction))
                return self.update_item

        #else:
        #    self.logger.warning("ModbusTCP: Modbus Function is mandatory!{0}".format(item))
        #    return None
####################################################################################################
##Item has changed, called by SmarthomeNG
####################################################################################################

    def update_item(self, item, caller=None, source=None, dest=None):
        if caller != 'ModbusTCP':
            value = int(item())
            mfunction = int(item.conf['modbus_function'])
            if self.has_iattr(item.conf, 'modbus_write'):
                madress = int(item.conf['modbus_write'])
                try:
                    #if self.client._connected:

                    if mfunction == 5:
                        #write_single_coil(bit_addr, bit_value)
                        val = self.client.write_coil(madress,
                                                     value,
                                                     unit=self._unit)
                        self.logger.debug(
                            'MODBUSTCP: Write on {0} with function{1} value {2}'
                            .format(madress, mfunction, value))
                    elif mfunction == 6:
                        #write_single_register(reg_addr, reg_value)
                        val = self.client.write_register(madress,
                                                         value,
                                                         unit=self._unit)
                        self.logger.debug(
                            'MODBUSTCP: Write on {0} with function{1} value {2}'
                            .format(madress, mfunction, value))
                    elif mfunction == 15:
                        #write_multiple_coils(reg_addr, reg_value)
                        bitarray = self.client.get_bits_from_int(
                            value, val_size=16, unit=self._unit)
                        val = self.client.write_multiple_coils(madress,
                                                               bitarray,
                                                               unit=self._unit)
                    elif mfunction == 16:
                        #write_multiple_registers(regs_addr, regs_value)
                        val = self.client.write_multiple_registers(
                            madress, value, unit=self._unit)

                    #if val.function_code > 0x80:
                    #    self.logger.error('MODBUSTCP: Could not write on {0} with function{1}, because Errorcode{2}'.format(madress, mfunction, val))
                    #else:
                    #    self.logger.error('MODBUSTCP: Client failure, not connected')
                except Exception as e:
                    self.logger.error(
                        'MODBUSTCP: ERROR; Could not write an OutWord, because {}'
                        .format(e))

####################################################################################################
#Read all Items, who are in self._adresses, called by Scheduler
####################################################################################################

    def _read(self):
        self._lock.acquire()
        try:
            #if self.client._connected:
            for adress in self._adresses:
                #self.logger.debug('MODBUSTCP: {0}'.format(adress))
                item = adress['item']
                mfunction = adress['mfunction']
                madress = adress['madress']
                #type = item.conf['type']
                if self.has_iattr(item.conf, 'modbus_format'):
                    mformat = item.conf['modbus_format']
                else:
                    mformat = 'raw'

                if mfunction == 1:  #Read Coil Status => Status der Ausgänge des MODBUS TCP Servers! ,bitorientiert
                    val = self.client.read_coils(madress, 1, unit=self._unit)
                    val = val.bits[0]
                    self.logger.debug(
                        'MODBUSTCP: Read from adress {0}, function {1}, item {2} = {3}'
                        .format(madress, mfunction, item, val))
                # #Read Input Status 0> STatus der Eingänge
                elif mfunction == 2:  #Read Discrete Inputs  => Status der Eingänge des MODBUS TCP Servers!, bitorientiert
                    # #read_discrete_inputs(bit_addr, bit_nb=1)
                    val = self.client.read_discrete_inputs(madress,
                                                           1,
                                                           unit=self._unit)
                    val = val.bits[0]
                    self.logger.debug(
                        'MODBUSTCP: Read from adress {0}, function {1}, item {2} = {3}'
                        .format(madress, mfunction, item, val))
                elif mfunction == 3:  #Read Holding Registers  => Status der Merker des MODBUS TCP Servers!, byteoriertiert
                    # #read_holding_registers(reg_addr, reg_nb=1)
                    #pass
                    val = self.client.read_holding_registers(madress,
                                                             1,
                                                             unit=self._unit)
                    #val = val.registers[0]
                elif mfunction == 4:  #Read INput Registers  => Status der Eingänge des MODBUS TCP Servers!, byteoriertiert
                    # #read_input_registers(reg_addr, reg_nb=1)

                    if '8' in mformat:
                        size = 1
                        value = self.client.read_input_registers(
                            madress, size, unit=self._unit)
                        decoder = BinaryPayloadDecoder.fromRegisters(
                            value.registers,
                            byteorder=self.byteorder,
                            wordorder=self.wordorder)
                        if 'uint' in mformat:
                            val = decoder.decode_8bit_uint()
                        else:
                            val = decoder.decode_8bit_int()
                    elif 'bits' in mformat:
                        value = self.client.read_input_registers(
                            madress, size, unit=self._unit)
                        decoder = BinaryPayloadDecoder.fromRegisters(
                            value.registers,
                            byteorder=self.byteorder,
                            wordorder=self.wordorder)
                        val = decoder.decode_bits()
                    elif '16' in mformat:
                        size = 1
                        value = self.client.read_input_registers(
                            madress, size, unit=self._unit)
                        decoder = BinaryPayloadDecoder.fromRegisters(
                            value.registers,
                            byteorder=self.byteorder,
                            wordorder=self.wordorder)
                        if 'uint' in mformat:
                            val = decoder.decode_16bit_uint()
                        else:
                            val = decoder.decode_16bit_int()

                    elif '32' in mformat:
                        size = 2
                        value = self.client.read_input_registers(
                            madress, size, unit=self._unit)
                        decoder = BinaryPayloadDecoder.fromRegisters(
                            value.registers,
                            byteorder=self.byteorder,
                            wordorder=self.wordorder)
                        if 'uint' in mformat:
                            val = decoder.decode_32bit_uint()
                        else:
                            val = decoder.decode_32bit_int()
                    elif '64' in mformat:
                        size = 4
                        value = self.client.read_input_registers(
                            madress, size, unit=self._unit)
                        decoder = BinaryPayloadDecoder.fromRegisters(
                            value.registers,
                            byteorder=self.byteorder,
                            wordorder=self.wordorder)
                        if 'uint' in mformat:
                            val = decoder.decode_64bit_uint()
                        else:
                            val = decoder.decode_64bit_int()
                    elif 'raw' in mformat:
                        value = self.client.read_input_registers(
                            madress, size, unit=self._unit)
                        decoder = BinaryPayloadDecoder.fromRegisters(
                            value.registers,
                            byteorder=self.byteorder,
                            wordorder=self.wordorder)
                        val = decoder.skip_bytes(8)
                    else:
                        val = 0
                    #decoded = {
                    # 'string': decoder.decode_string(8),
                    # 'bits': decoder.decode_bits(),
                    #'8int': decoder.decode_8bit_int(),
                    # '8uint': decoder.decode_8bit_uint(),
                    #'16int': decoder.decode_16bit_int(),
                    # '16uint': decoder.decode_16bit_uint(),
                    #'32int': decoder.decode_32bit_int(),
                    # '32uint': decoder.decode_32bit_uint(),
                    # '32float': decoder.decode_32bit_float(),

                    # '64int': decoder.decode_64bit_int(),
                    # '64uint': decoder.decode_64bit_uint(),
                    # 'raw': decoder.skip_bytes(8),
                    # '64float': decoder.decode_64bit_float(),
                    #}

                if value == None:
                    self.logger.error(
                        'MODBUSTCP: Could not read from {0} with function {1}'.
                        format(madress, mfunction))
                else:
                    #val = decoded[mformat]
                    self.logger.debug(
                        'MODBUSTCP: Read from adress {0}, with size {1},function {2} item {3} = {4}'
                        .format(madress, size, mfunction, item, val))
                    item(val, 'ModbusTCP')
        except Exception as e:
            self.logger.error(
                'MODBUSTCP: Could not read from adress {0} with function {1}, because {2}'
                .format(madress, mfunction, e))
        finally:
            self._lock.release()
####################################################################################################
#wandelt str in binary ohne führendes 0b
#und invertiert auf wunsch das Ergebnis!
#
#
#
####################################################################################################

    def toBinary2(self, n, invert=1):  ##
        byte = '{:08b}'.format(n)

        i = int(16) - len(byte)
        ausgabe = ""
        for x in range(0, i):
            ausgabe = "0" + ausgabe
        ausgabe = ausgabe + byte
        if invert == 1:  #invertieren
            ausgabe = ausgabe[::-1]
        return ausgabe

    def toBinary(self, n, invert=0):  ##
        byte = '{:08b}'.format(n)
        if invert == 1:  #invertieren
            byte = byte[::-1]
        ausgabe = []
        if byte == '00000000':
            ausgabe.append('00000000')
            ausgabe.append('00000000')
        elif byte < '256':
            ausgabe.append(byte[0:8])
            ausgabe.append('00000000')
        else:
            ausgabe.append(byte[0:8])
            ausgabe.append(byte[8:17])
        return ausgabe

    def de5001(self, value):  #8bit 0-100 auf 0-255 normieren
        if value > 255:
            value = 255
        elif value < 0:
            value = 0
        return int(round(value * 2.55))

    def en5001(self, value):  #8bit auf 0-100 normieren
        if value > 255:
            value = 255
        elif value < 0:
            value = 0
        return (round((value / 2.55), 2))
####################################################################################################
#Helper FUnction to split modbus register
####################################################################################################

    def split_ga(self, ga):
        if '|' in ga:
            type, dst = ga.split('|')
            if type in self.types.keys():
                area = self.types[type]
            else:
                area = 'DB'
        else:
            area = 'DB'
        s7area = areas[area]

        #split db\byte\bit
        ret_s7_num = re.findall(r'\d+', ga)

        if area == 'DB':  #db = 3  []
            if len(ret_s7_num) > 2:
                #dbnum, byte,bit = ret_s7_num
                dbnum = int(ret_s7_num[0])
                byte = int(ret_s7_num[1])
                bit = int(ret_s7_num[2])
            else:
                dbnum = int(ret_s7_num[0])
                byte = int(ret_s7_num[1])
                bit = 0
        else:  # other only 2
            dbnum = 0
            if len(ret_s7_num) > 1:
                byte = int(ret_s7_num[0])
                bit = int(ret_s7_num[1])
            else:
                byte = int(ret_s7_num[0])
                bit = 0

        self.logger.debug("S7: split_ga {0}".format([s7area, dbnum, byte,
                                                     bit]))
        return [s7area, dbnum, byte, bit]
Пример #32
0
class Modbus_Driver(object):
    def __init__(self, config_file, config_section='modbus', **kwargs):
        # Use a config section if the config file is being shared with other
        # parts of a project. **kwargs can contain a variable amount of
        if (isinstance(config_file,str)):

            with open(config_file) as f:
                modbusConfig = yaml.safe_load(f)
        else:
            modbusConfig = config_file

        modbus_section = config_section

        self.BYTE_ORDER_DICT = {}
        self.WORD_ORDER_DICT = {}
        self.input_register_dict = {}
        self.holding_register_dict = {}
        self.coil_register_dict = {}
        self.discrete_register_dict = {}

        self.input_registers = {}
        self.holding_registers = {}
        self.coil_registers = {}
        self.discrete_registers = {}
        self.MODBUS_TYPE = modbusConfig[modbus_section]['modbus_type']
        # Check to see if unit id is a list, if it is then set flag that it is a
        # list
        self.UNIT_ID = modbusConfig[modbus_section]['UNIT_ID']
        if isinstance(self.UNIT_ID, list):
            self.UNIT_ID_LIST = self.UNIT_ID
            #Set default UNIT_ID as first UNIT_ID in list
            self.UNIT_ID = int(self.UNIT_ID_LIST[0])
        else:
            # Make a unit id list from the non-list definition for compatibility
            # reasons of previous configs. This also eliminates the possibility
            # of error in calling get_data_all_devices() on a config with a non
            # list definition
            self.UNIT_ID_LIST = []
            self.UNIT_ID_LIST.append(self.UNIT_ID)
        # Start logging if enabled in config
        self.LOGGING_FLAG = modbusConfig[modbus_section]['enable_logging']
        if self.LOGGING_FLAG == False:
            #Start client logging for trouble shooting
            logging.basicConfig()
            log = logging.getLogger()
            log.setLevel(logging.ERROR)

        # Start appropriate client based on the type specified in the config
        if self.MODBUS_TYPE == 'serial':
            self.METHOD = modbusConfig[modbus_section]['method']
            self.SERIAL_PORT = modbusConfig[modbus_section]['serial_port']
            self.STOPBITS = modbusConfig[modbus_section]['stopbits']
            self.BYTESIZE = modbusConfig[modbus_section]['bytesize']
            self.PARITY = modbusConfig[modbus_section]['parity']
            self.BAUDRATE = modbusConfig[modbus_section]['baudrate']
        elif self.MODBUS_TYPE == 'tcp':
            self.IP_ADDRESS = modbusConfig[modbus_section]['ip']
            self.PORT = modbusConfig[modbus_section]['port']
        else:
            print("Invalid modbus type")
            exit

        # Set the byte order as big or little endian
        if modbusConfig[modbus_section]['byte_order'] == 'big':
            self.BYTE_ORDER = Endian.Big
            self.BYTE_ORDER_DICT[self.UNIT_ID] = Endian.Big
        elif modbusConfig[modbus_section]['byte_order'] == 'little':
            self.BYTE_ORDER = Endian.Little
            self.BYTE_ORDER_DICT[self.UNIT_ID] = Endian.Little
        else:
            print("invalid byte order") # change to except later
            exit()
        # Set the word order as big or little endian
        if modbusConfig[modbus_section]['word_order'] == 'big':
            self.WORD_ORDER = Endian.Big
            self.WORD_ORDER_DICT[self.UNIT_ID] = Endian.Big

        elif modbusConfig[modbus_section]['word_order'] == 'little':
            self.WORD_ORDER = Endian.Little
            self.WORD_ORDER_DICT[self.UNIT_ID] = Endian.Little
        else:
            print("invalid byte order") # change to except later
            exit()

        # Read in all registers specified in the YAML config
        self.coil_register_dict = modbusConfig[modbus_section]['coil_registers']
        self.discrete_register_dict = modbusConfig[modbus_section]['discrete_registers']
        self.holding_register_dict = modbusConfig[modbus_section]['holding_registers']
        self.input_register_dict = modbusConfig[modbus_section]['input_registers']

        self.coil_registers[self.UNIT_ID] = self.coil_register_dict
        self.discrete_registers[self.UNIT_ID] = self.discrete_register_dict
        self.holding_registers[self.UNIT_ID] = self.holding_register_dict
        self.input_registers[self.UNIT_ID] = self.input_register_dict
        #print(self.holding_registers)

        # Add single device that is either specified in config_section parameter
        # or a single device config file
        for current_device in self.UNIT_ID_LIST:
            self.coil_registers[current_device] = self.coil_register_dict
            self.discrete_registers[current_device] = self.discrete_register_dict
            self.holding_registers[current_device] = self.holding_register_dict
            self.input_registers[current_device] = self.input_register_dict
            # Set the byte order as big or little endian
            if modbusConfig[modbus_section]['byte_order'] == 'big':
                self.BYTE_ORDER_DICT[current_device] = Endian.Big
            elif modbusConfig[modbus_section]['byte_order'] == 'little':
                self.BYTE_ORDER_DICT[current_device] = Endian.Little
            else:
                print("invalid byte order") # change to except later
                exit()
            # Set the word order as big or little endian
            if modbusConfig[modbus_section]['word_order'] == 'big':
                self.WORD_ORDER_DICT[current_device] = Endian.Big
            elif modbusConfig[modbus_section]['word_order'] == 'little':
                self.WORD_ORDER_DICT[current_device] = Endian.Little
            else:
                print("invalid word order") # change to except later
                exit()

        # Apply register offset if specified
        self.OFFSET_REGISTERS = modbusConfig[modbus_section]['OFFSET_REGISTERS']
        for key in self.holding_register_dict:
            self.holding_register_dict[key][0] -= self.OFFSET_REGISTERS

        # Add devices that were specified with **kwargs
        for device_name, modbus_section in kwargs.items():
            # The Device ID is used as the key in a dictionary for all settings
            # that could potentially differ between devices. Since all of the
            # functions already have been updated to take in a UNIT_ID this
            # can be used to retrieve the appropriate setting for the device.

            # TODO Handle case where the config section has a list of the same
            # device.

            current_device = modbusConfig[modbus_section]['UNIT_ID']
            #print(type(current_device))
            # TODO make this a for loop for each ID
            #current_device = current_device[0]
            self.UNIT_ID_LIST.append(int(current_device))

            if modbusConfig[modbus_section]['byte_order'] == 'big':
                self.BYTE_ORDER_DICT[current_device] = Endian.Big
            elif modbusConfig[modbus_section]['byte_order'] == 'little':
                self.BYTE_ORDER_DICT[current_device] = Endian.Little
            # Set the word order as big or little endian
            if modbusConfig[modbus_section]['word_order'] == 'big':
                self.WORD_ORDER_DICT[current_device] = Endian.Big
            elif modbusConfig[modbus_section]['word_order'] == 'little':
                self.WORD_ORDER_DICT[current_device] = Endian.Little
            else:
                print("invalid word order") # change to except later
                exit()
            # Read in all registers specified in the YAML config
            self.coil_register_dict = modbusConfig[modbus_section]['coil_registers']
            self.discrete_register_dict = modbusConfig[modbus_section]['discrete_registers']
            self.holding_register_dict = modbusConfig[modbus_section]['holding_registers']
            self.input_register_dict = modbusConfig[modbus_section]['input_registers']

            self.coil_registers[current_device] = self.coil_register_dict
            self.discrete_registers[current_device] = self.discrete_register_dict
            self.holding_registers[current_device] = self.holding_register_dict
            self.input_registers[current_device] = self.input_register_dict
            #print(self.holding_register_dict)
            '''
            # Read in all registers specified in the YAML config
            self.coil_registers[current_device] = modbusConfig[modbus_section]['coil_registers']
            self.discrete_registers[current_device] = modbusConfig[modbus_section]['discrete_registers']
            self.holding_registers[current_device] = modbusConfig[modbus_section]['holding_registers']
            self.input_register_dict[current_device] = modbusConfig[modbus_section]['input_registers']
            '''

            # Apply register offset if specified
            # TODO fix this for one device as well as multiple
            """
            self.OFFSET_REGISTERS_DICT[current_device] = modbusConfig[modbus_section]['OFFSET_REGISTERS']
            for key in self.holding_register_dict:
                self.holding_register_dict[key][0] -= self.OFFSET_REGISTERS
            """
            #print(self.holding_registers)



    def initialize_modbus(self):
        """
        initalize correct client according to type specified in config:
            'tcp' or 'serial'
        """
        if self.MODBUS_TYPE == 'serial':
            self.client= ModbusSerialClient(
                    method      = self.METHOD,
                    port        = self.SERIAL_PORT,
                    stopbits    = self.STOPBITS,
                    bytesize    = self.BYTESIZE, 
                    parity      = self.PARITY,
                    baudrate    = self.BAUDRATE
                )
            connection = self.client.connect()

        if self.MODBUS_TYPE == 'tcp':
            self.client = ModbusTcpClient(self.IP_ADDRESS,port=self.PORT)
        '''
        rr = self.read_register_raw(0x601,1,247)
        decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
        output = decoder.decode_16bit_int()
        print(output)
        '''
        #rr = self.read_register_raw(1001,2,7)
        '''decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
        '''


    def reconnect(self):
        try:
            self.client.close()
        finally:
            self.initialize_modbus()

    def write_single_register(self,register,value, unit=None):
        """
        :param register: address of reigster to write
        :param value: Unsigned short
        :returns: Status of write
        """
        if (unit is None):
            unit = self.UNIT_ID
        response = self.client.write_register(register,value,unit)
        return response

    def write_data(self,register,value):
        response = self.client.write_register(register,value,unit= self.UNIT_ID)
        return response

    def write_register(self,register_name,value, unit=None):
        """
        :param register_name: register key from holding register dictionary
            generated by yaml config
        :param value: value to write to register
        :returns: -- Nothing
        """
        # TODO add the ability to discern which settings will be appropriate for
        # the device that is being written to
        if (unit is None):
            unit = self.UNIT_ID
        '''
        builder = BinaryPayloadBuilder(byteorder=self.BYTE_ORDER,
            wordorder=self.WORD_ORDER_DICT[unit])
        '''
        builder = BinaryPayloadBuilder(byteorder=self.BYTE_ORDER_DICT[unit],
            wordorder=self.WORD_ORDER_DICT[unit])
        # This will change depending on the device that is being connected
        # potentially so it has to be correleated to the device ID

        if (self.holding_register_dict[register_name][1] == '8int'):
            builder.add_8bit_int(value)
        elif (self.holding_register_dict[register_name][1] == '8uint'):
            builder.add_8bit_uint(value)
        elif (self.holding_register_dict[register_name][1] == '16int'):
            builder.add_16bit_int(value)
        elif (self.holding_register_dict[register_name][1] == '16uint'):
            builder.add_16bit_uint(value)
        elif (self.holding_register_dict[register_name][1] == '32int'):
            builder.add_32bit_int(value)
        elif (self.holding_register_dict[register_name][1] == '32uint'):
            builder.add_32bit_uint(value)
        elif (self.holding_register_dict[register_name][1] == '32float'):
            builder.add_32bit_float(value)
        elif (self.holding_register_dict[register_name][1] == '64int'):
            builder.add_64bit_int(value)
        elif (self.holding_register_dict[register_name][1] == '64uint'):
            builder.add_64bit_uint(value)
        elif (self.holding_register_dict[register_name][1] == '64float'):
            builder.add_64bit_float(value)
        else:
            print("Bad type")
            exit()
        payload = builder.build()
        self.client.write_registers(self.holding_register_dict[register_name][0],
            payload, skip_encode=True, unit = self.UNIT_ID)

    def write_coil(self,register,value, unit=None):
        """
        :param register_name: register key from holding register dictionary
            generated by yaml config
        :param value: value to write to register
        :returns:
        """
        # TODO mention what type the value needs to be for value
        if (unit is None):
            unit = self.UNIT_ID

        response = self.client.write_coil(register,value,unit)
        return response

    def read_coil(self,register, unit=None):
        """
        :param register: coil register address to read
        :returns: value stored in coil register
        """
        # TODO mention what type the value needs to be for value
        if (unit is None):
            unit = self.UNIT_ID

        rr = self.client.read_coils(register, 1, unit=unit)
        return rr.bits[0]

    def read_discrete(self,register,unit=None):
        """
        :param register: discrete register address to read
        :returns: value stored in coil register
        """
        if (unit is None):
            unit = self.UNIT_ID

        rr = self.client.read_discrete_inputs(register, count=1,unit=unit)
        return rr.bits[0]

    def read_register_raw(self,register,length, unit=None):
        """
        :param register: base holding register address to read
        :param length: amount of registers to read to encompass all of the data necessary
            for the type
        :returns: A deferred response handle
        """
        if (unit is None):
            unit = self.UNIT_ID

        response = self.client.read_holding_registers(register,length,unit=unit)
        return response

    def read_input_raw(self,register,length, unit=None):
        """
        :param register: base input register address to read
        :param length: amount of registers to read to encompass all of the data necessary
            for the type
        :returns: A deferred response handle
        """
        if (unit is None):
            unit = self.UNIT_ID

        response = self.client.read_input_registers(register,length,unit=unit)
        return response

    def decode_register(self,register,type, unit=None):
        #print(unit)
        #print(type(unit))
        """
        :param register: holding register address to retrieve
        :param type: type to interpret the registers retrieved as
        :returns: data in the type specified

        Based on the type provided, this function retrieves the values contained
        in the register address specfied plus the amount necessary to encompass
        the the type. For example, if 32int is specified with an address of 200
        the registers accessed would be 200 and 201.

        The types accepted are listed in the table below along with their length
        |   Type          | Length (registers) |
        | ------------- |:------------------:|
        |        ignore |                  1 |
        |          8int |                  1 |
        |         8uint |                  1 |
        |         16int |                  1 |
        |        16uint |                  1 |
        |         32int |                  2 |
        |        32uint |                  2 |
        |       32float |                  2 |
        |         64int |                  4 |
        |        64uint |                  4 |
        |       64float |                  4 |
        """
        if (unit is None):
            unit = self.UNIT_ID
        #omitting string for now since it requires a specified length
        if type == '8int':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_8bit_int()

        elif type == '8uint':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_8bit_uint()
        elif type == '16int':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_16bit_int()
        elif type == '16uint':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_16bit_uint()
        elif type == '32int':
            rr = self.read_register_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_32bit_int()
        elif type == '32uint':
            rr = self.read_register_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_32bit_uint()
        elif type == '32float':
            rr = self.read_register_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_32bit_float()
        elif type == '64int':
            rr = self.read_register_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_64bit_int()
        elif type == '64uint':
            rr = self.read_register_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_64bit_uint()
        elif type == 'ignore':
            rr = self.read_register_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.skip_bytes(8)
        elif type == '64float':
            rr = self.read_register_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_64bit_float()
        else:
            print("Wrong type specified")
            exit()

        return output

    def decode_input_register(self,register,type, unit=None):
        """
        :param register: input register address to retrieve
        :param type: type to interpret the registers retrieved as
        :returns: data in the type specified

        Based on the type provided, this function retrieves the values contained
        in the register address specfied plus the amount necessary to encompass
        the the type. For example, if 32int is specified with an address of 200
        the registers accessed would be 200 and 201.

        The types accepted are listed in the table below along with their length
        |   Type          | Length (registers) |
        | ------------- |:------------------:|
        |        ignore |                  1 |
        |          8int |                  1 |
        |         8uint |                  1 |
        |         16int |                  1 |
        |        16uint |                  1 |
        |         32int |                  2 |
        |        32uint |                  2 |
        |       32float |                  2 |
        |         64int |                  4 |
        |        64uint |                  4 |
        |       64float |                  4 |
        """
        if (unit is None):
            unit = self.UNIT_ID
        #omitting string for now since it requires a specified length
        if type == '8int':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_8bit_int()

        elif type == '8uint':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit][unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_8bit_uint()
        elif type == '16int':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_16bit_int()
        elif type == '16uint':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_16bit_uint()
        elif type == '32int':
            rr = self.read_input_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_32bit_int()
        elif type == '32uint':
            rr = self.read_input_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_32bit_uint()
        elif type == '32float':
            rr = self.read_input_raw(register,2,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_32bit_float()
        elif type == '64int':
            rr = self.read_input_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_64bit_int()
        elif type == '64uint':
            rr = self.read_input_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_64bit_uint()
        elif type == 'ignore':
            rr = self.read_input_raw(register,1,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.skip_bytes(8)
        elif type == '64float':
            rr = self.read_input_raw(register,4,unit)
            decoder = BinaryPayloadDecoder.fromRegisters(
                    rr.registers,
                    byteorder=self.BYTE_ORDER_DICT[unit],
                    wordorder=self.WORD_ORDER_DICT[unit])
            output = decoder.decode_64bit_float()
        else:
            print("Wrong type specified")
            exit()

        return output

    def read_register(self,register_name):
        response = self.decode_register(self.holding_register_dict[register_name][0],
            self.holding_register_dict[register_name][1])
        return response

    def read_input_raw(self,register_name):
        response = self.decode_input_register(self.holding_register_dict[register_name][0],
            self.holding_register_dict[register_name][1])
        return response


    def get_data(self,unit=None):
        """
        :returns: Dictionary containing the value retrieved for each register
        contained in the YAML config file, register names cannot be repeated
        or the register will be overwritten
        """
        output = {}

        if unit is None:
            unit = self.UNIT_ID

        for key in self.coil_registers[unit]:
            output[key] = self.read_coil(self.coil_registers[unit][key][0],unit)

        for key in self.discrete_registers[unit]:
            output[key] = self.read_discrete(self.discrete_registers[unit][key][0],unit)

        for key in self.input_registers[unit]:
            output[key] = self.decode_input_register(self.input_registers[unit][key][0],self.input_registers[unit][key][1],unit)
            
        for key in self.holding_registers[unit]:
            if (len(self.holding_registers[unit][key]) == 3):
                # Check Read/Write Flag
                if (self.holding_registers[unit][key][2].find('R') != -1):
                    output[key] = self.decode_register(self.holding_registers[unit][key][0],self.holding_registers[unit][key][1],unit)
            else:
                # Register list does not contain a Read/Write Flag assume R
                output[key] = self.decode_register(self.holding_registers[unit][key][0],self.holding_registers[unit][key][1],unit)

        return output

    def get_data_all_devices(self):
        reg_data_dict = {}
        cnt = 1
        for dev_id in self.UNIT_ID_LIST:
            new_key = str(dev_id)
            if str(dev_id) in reg_data_dict:
                new_key = new_key + '_' + str(cnt)
                cnt += 1
            reg_data_dict[new_key] = self.get_data(dev_id)
        return reg_data_dict
    def kill_modbus(self):
        """
        Closes connection with Modbus Slave
        """
        self.client.close()
Пример #33
0
# blocks for the two sets, so a change to one is a change to the other.
# Keep both of these cases in mind when testing as the following will
# _only_ pass with the supplied async modbus server (script supplied).
#---------------------------------------------------------------------------# 
rq = client.write_coil(1, True)
rr = client.read_coils(1,1)
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.bits[0] == True)          # test the expected value

rq = client.write_coils(1, [True]*8)
rr = client.read_coils(1,8)
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.bits == [True]*8)         # test the expected value

rq = client.write_coils(1, [False]*8)
rr = client.read_discrete_inputs(1,8)
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.bits == [True]*8)         # test the expected value

rq = client.write_register(1, 10)
rr = client.read_holding_registers(1,1)
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.registers[0] == 10)       # test the expected value

rq = client.write_registers(1, [10]*8)
rr = client.read_input_registers(1,8)
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.registers == [17]*8)      # test the expected value

arguments = {
    'read_address':    1,
Пример #34
0
class VisualizerApp(Ui_MainWindow):
    def __init__(self, main_window):
        self.setupUi(main_window)

        self.connect_slots()
        self.init_poll_table()
        self.update_poll_table_column_headers()

        self.configure_modbus_client()

        self.connected = False

    def connect_slots(self):
        self.singlePollPushButton.clicked.connect(self.single_poll)
        self.startRegisterSpinBox.valueChanged.connect(
            self.update_poll_table_column_headers)

    def init_poll_table(self):
        """
        Initialize the table with QTableWidgetItem objects that are empty strings.
        """
        num_rows = self.pollTable.rowCount()
        num_cols = self.pollTable.columnCount()

        for j in range(num_cols):
            for i in range(num_rows):
                self.pollTable.setItem(i, j, QTableWidgetItem(""))

    def update_poll_table_column_headers(self):
        self.clear_poll_table()  # Avoids confusion

        start = self.startRegisterSpinBox.value()
        num_cols = self.pollTable.columnCount()
        num_rows = self.pollTable.rowCount()

        for i in range(num_cols):
            self.pollTable.horizontalHeaderItem(i).setText(
                str(start + i * num_rows))

    def clear_poll_table(self):
        num_rows = self.pollTable.rowCount()
        num_cols = self.pollTable.columnCount()

        for j in range(num_cols):
            for i in range(num_rows):
                self.pollTable.item(i, j).setText("")

    def write_poll_table(self, data):
        self.clear_poll_table()
        num_rows = self.pollTable.rowCount()

        cur_col = 0
        for i, datum in enumerate(data):
            self.pollTable.item(i % 10, cur_col).setText(str(datum))
            #self.pollTable.setItem(i % 10, cur_col, QTableWidgetItem(str(datum)))
            if (i + 1) % num_rows == 0:
                cur_col += 1

    def configure_modbus_client(self):
        tcp_mode = self.tcpRadioButton.isChecked()
        rtu_mode = self.rtuRadioButton.isChecked()

        if rtu_mode:
            pass
        elif tcp_mode:
            host = self.tcpHostLineEdit.text()
            port = self.tcpPortLineEdit.text()
            self.client = ModbusTcpClient(host, port)

        self.connected = self.client.connect()

        if not self.connected:
            self.write_console("Could not connect.")

        else:
            self.write_console("Connection Successful.")

    def single_poll(self):
        data = self.poll_modbus_data()
        self.write_poll_table(data)

        if data:
            self.write_console("Poll Successful")

    def poll_modbus_data(self):
        self.configure_modbus_client()

        if not self.connected:
            return []

        start = self.startRegisterSpinBox.value()
        length = self.numberOfRegistersSpinBox.value()
        register_type = self.registerTypeComboBox.currentText()

        if register_type == "Coils":
            rr = self.client.read_coils(start, length)
            data = rr.bits[:length]

        elif register_type == "Discrete Inputs":
            rr = self.client.read_discrete_inputs(start, length)
            data = rr.bits[:length]

        elif register_type == "Input Registers":
            rr = self.client.read_input_registers(start, length)
            data = rr.registers

        elif register_type == "Holding Registers":
            rr = self.client.read_holding_registers(start, length)
            data = rr.registers

        else:
            self.write_console("Unknown Register Type.")
            data = []

        return data

    def write_console(self, msg):
        self.consoleLineEdit.setText(msg)

    def exit(self):
        QApplication.quit()
Пример #35
0
# If the returned output quantity is not a multiple of eight,
# the remaining bits in the final data byte will be padded with zeros
# (toward the high order end of the byte).

resp.extend([False] * 3)
assert (rr.bits == resp)  # test the expected value

log.debug("Write to multiple coils and read back - test 2")
rq = client.write_coils(1, [False] * 8, unit=1)
rr = client.read_coils(1, 8, unit=1)
assert (rq.function_code < 0x80)  # test that we are not an error
assert (rr.bits == [False] * 8)  # test the expected value

log.debug("Read discrete inputs")
rr = client.read_discrete_inputs(0, 8, unit=1)
assert (rq.function_code < 0x80)  # test that we are not an error

log.debug("Write to a holding register and read back")
rq = client.write_register(1, 10, unit=1)
rr = client.read_holding_registers(1, 1, unit=1)
assert (rq.function_code < 0x80)  # test that we are not an error
assert (rr.registers[0] == 10)  # test the expected value

log.debug("Write to multiple holding registers and read back")
rq = client.write_registers(1, [10] * 8, unit=1)
rr = client.read_holding_registers(1, 8, unit=1)
assert (rq.function_code < 0x80)  # test that we are not an error
assert (rr.registers == [10] * 8)  # test the expected value

log.debug("Read input registers")
Пример #36
0
assert (rq.function_code < 0x80)  # test that we are not an error
assert (rr.bits[0] == True)  # test the expected value
print rr.bits

rq = client.write_coils(1, [True] * 8)
rr = client.read_coils(1, 8)
assert (rq.function_code < 0x80)  # test that we are not an error
assert (rr.bits == [True] * 8)  # test the expected value
print rr.bits

rq = client.write_coils(1, [False] * 8)
rr = client.read_coils(1, 8)
assert (rq.function_code < 0x80)  # test that we are not an error
print rr.bits
assert (rr.bits == [False] * 8)  # test the expected value
'''
client.read_discrete_inputs(address, count, unit)
rq = client.write_coils(1, [False]*8)
rr = client.read_discrete_inputs(1,8)
print "discrete 1", rr.bits
rq = client.write_coils(2, [False]*8)
rr = client.read_discrete_inputs(2,8)
print "discrete 2", rr.bits
rq = client.write_coils(0, [False]*8)
rr = client.read_discrete_inputs(0,8)
print "discrete 0", rr.bits
assert(rq.function_code < 0x80)     # test that we are not an error
assert(rr.bits == [False]*8)         # test the expected value
'''
rq = client.write_register(1, 10)
rr = client.read_holding_registers(1, 1)
Пример #37
0
    elif args.mode == 'r':

        # NOTE: read_holding_registers
        if args.type == 'HR':
            hr_read = client.read_holding_registers(args.offset,
                                                    count=args.count)
            assert (hr_read.function_code < 0x80)
            print(hr_read.registers[0:args.count])

        # NOTE: read_holding_registers
        elif args.type == 'IR':
            ir_read = client.read_input_registers(args.offset,
                                                  count=args.count)
            assert (ir_read.function_code < 0x80)
            print(ir_read.registers[0:args.count])

        # NOTE: read_discrete_inputs
        elif args.type == 'DI':
            di_read = client.read_discrete_inputs(args.offset,
                                                  count=args.count)
            assert (di_read.function_code < 0x80)
            print(di_read.bits)

        # NOTE: read_discrete_inputs
        elif args.type == 'CO':
            co_read = client.read_coils(args.offset, count=args.count)
            assert (co_read.function_code < 0x80)
            print(co_read.bits)

    client.close()
Пример #38
0
    for i in range(0, len(totusTemps)):
        print totusTemps[i] + " = " + str(result.getRegister(i)/10.0) + "\xb0C"# scaling is 10



    # read alarms
    totusAlarms = [
                "ALARM/System/HL/State",
                "ALARM/System/HHLL/State"
                ]

    numInputs = 2
    startAddress = 100
    slaveID = 1
    result = client.read_discrete_inputs(startAddress, numInputs, slaveID)


    for i in range(0, len(totusAlarms)):
        print totusAlarms[i] + " = " + str(result.getBit(i))


    # read DGA float32 gases
    totusDGA = [
                "DGA/SourceA/CH4",
                "DGA/SourceA/C2H6",
                "DGA/SourceA/C2H4",
                "DGA/SourceA/C2H2",
                "DGA/SourceA/CO",
                "DGA/SourceA/CO2",
                "DGA/SourceA/O2",