Esempio n. 1
0
def test_close_raises_commerror_on_socket_close_exception():
    with mock.patch.object(Socket, 'close') as mock_close:
        mock_close.side_effect = Exception
        with pytest.raises(CommError):
            driver = CIPDriver(CONNECT_PATH)
            driver._sock = Socket()
            driver.close()
Esempio n. 2
0
def test_cip_get_module_info_raises_response_error_if_response_falsy():
    with mock.patch.object(CIPDriver,
                           'generic_message') as mock_generic_message:
        mock_generic_message.return_value = False
        with pytest.raises(ResponseError):
            driver = CIPDriver(CONNECT_PATH)
            driver.get_module_info(1)

        assert mock_generic_message.called
Esempio n. 3
0
def test__forward_close_returns_true_if_response():
    driver = CIPDriver(CONNECT_PATH)
    driver._session = 1
    response = (
        b"o\x00\x1e\x00\x02\x16\x02\x0b\x00\x00\x00\x00_pycomm_"
        b"\x00\x00\x00\x00\x00\x00\x00\x00\n\x00\x02\x00\x00\x00"
        b"\x00\x00\xb2\x00\x0e\x00\xce\x00\x00\x00'\x04\t\x10\xd6\x9c\x06=\x00\x00"
    )
    driver._sock = Mocket(response)
    assert driver._forward_close()
Esempio n. 4
0
def discoverPLCs(): # Function to discover any PLC on the network
    ips, slots, progName = [], [], []
    try:
        discovery = CIPDriver.discover() # Return list of all CIP devices on the network
        for device in discovery: # Go through discovery list and append any PLC#'s to a list
            if device['product_type'] == "Programmable Logic Controller":
                ips.append(device['ip_address'])        
        if len(ips) > 0: # Print the discovered PLC's, if there are any
            ips.sort() # Sort the IP address in ascending order
            table = Table(box=box.ROUNDED) # Create table 
            table.add_column('#', justify='center') # Add column
            table.add_column('Device Type', justify='center') # Add column
            table.add_column('IP Address', justify='center') # Add column
            table.add_column('Slot #', justify='center') # Add column
            table.add_column('Program Name', justify='center') # Add column
            for i, ip in enumerate(ips): # Add row for each PLC discovered
                slots.append('Unknown')
                progName.append('Unknown')
                for slot in range(1, 18):
                    try:
                        plc = LogixDriver(f'{plc}/{str(slot)}', init_tags=False)
                        if plc.open():
                            slots[i] = slot
                            progName[i] = plc.get_plc_name()
                            plc.close()
                            break
                    except:
                        continue
                table.add_row(str(i+1), 'Programmable Logic Controller', ip, str(slots[i]), progName[i])
            print(table)
        else:
            print("No PLC's discovered on the network")
    except Exception:
        traceback.print_exc()
Esempio n. 5
0
def test_discover():
    from pycomm3 import CIPDriver
    devices = CIPDriver.discover()

    expected = [
        {'encap_protocol_version': 1, 'ip_address': '192.168.1.237',
        'vendor': 'Rockwell Automation/Allen-Bradley', 'product_type': 'Communications Adapter',
        'product_code': 185, 'revision': {'major': 2, 'minor': 7},

        'serial': '73015738', 'product_name': '1763-L16BWA B/7.00', 'state': 0},
       {'encap_protocol_version': 1, 'ip_address': '192.168.1.236',
        'vendor': 'Rockwell Automation/Allen-Bradley', 'product_type':
        'Communications Adapter', 'product_code': 191, 'revision': {'major': 20, 'minor': 19},
        'serial': 'c01ebe90', 'product_name': '1769-L23E-QBFC1 Ethernet Port', 'state': 3},

       # {'encap_protocol_version': 1, 'ip_address': '192.168.1.125', 'vendor': 'Rockwell Software, Inc.',
       #  'product_type': 'Communications Adapter', 'product_code': 115, 'revision': {'major': 12, 'minor': 1},
       #   'serial': '21ac1903', 'product_name': 'DESKTOP-907P98D', 'state': 255}
    ]

    # status can change based on number of connections or other reasons
    # just check to make sure it has a value then remove it from the
    # rest of the device info
    # for device in devices:
    #     assert 'status' in device
    #     del device['status']
    #     assert device in expected
    for device in devices:
        assert 'ip_address' in device
        assert 'vendor' in device
        assert 'product_type' in device
        assert 'product_code' in device
        assert 'revision' in device
Esempio n. 6
0
def link_status():
    message_path = '10.10.10.100/bp/2'

    with CIPDriver(message_path) as device:
        data = device.generic_message(
            service=Services.get_attribute_single,
            class_code=b'\xf6',  # Values from RA Knowledgebase
            instance=
            1,  # For multiport devices, change to "2" for second port, "3" for third port.
            # For CompactLogix, front port is "1" and back port is "2".
            attribute=2,  # Values from RA Knowledgebase
            data_type=INT,
            connected=False,
            unconnected_send=True,
            route_path=True,
            name='LinkStatus')
        # Prints the binary representation of the link status. The definition of the bits are:
        #   Bit 0 - Link Status - 0 means inactive link (Link Lost), 1 means active link.
        #   Bit 1 - Half/Full Duplex - 0 means half duplex, 1 means full duplex
        #   Bit 2 to 4 - Binary representation of auto-negotiation and speed detection status:
        #       0 = Auto-negotiation in progress
        #       1 = Auto-negotiation and speed detection failed
        #       2 = Auto-negotiation failed, speed detected
        #       3 = Auto-negotiation successful and speed detected
        #       4 = Manually forced speed and duplex
        #   Bit 5 - Setting Requires Reset - if 1, a manual setting requires resetting of the module
        #   Bit 6 - Local Hardware Fault - 0 indicates no hardware faults, 1 indicates a fault detected.
        print(bin(data.value))
Esempio n. 7
0
def test_context_manager_calls_open_close():
    with mock.patch.object(CIPDriver, 'open') as mock_close, \
         mock.patch.object(CIPDriver, 'close') as mock_open:
        with CIPDriver(CONNECT_PATH) as driver:
            ...
        assert mock_open.called
        assert mock_close.called
Esempio n. 8
0
def read_params():
    connection = connection_setup()
    drive_path = connection[0]
    conn_type = connection[1]
    if conn_type == 'p':
        connected_send = False
        unconnected_send = True
        route_path = False
    elif conn_type == 'd':
        connected_send = True
        unconnected_send = False
        route_path = True

    print("Enter a parameter to read:")
    param_to_read = input('>>> ')

    with CIPDriver(drive_path) as drive:
        param = drive.generic_message(service=Services.get_attribute_single,
                                      class_code=b'\x93',
                                      instance=int(param_to_read),
                                      attribute=b'\x09',
                                      data_type=INT,
                                      connected=connected_send,
                                      unconnected_send=unconnected_send,
                                      route_path=route_path,
                                      name='PF525_Param')
        print(param)
Esempio n. 9
0
def upload_eds():
    """
    Uploads the EDS and ICO files from the device and saves the files.
    """
    with CIPDriver('192.168.1.236') as driver:
        if initiate_transfer(driver):
            file_data = upload_file(driver)
            encoding = get_file_encoding(driver)

            if encoding == 'zlib':
                # in this case the file has both the eds and ico files in it
                files = decompress_eds(file_data)

                for filename, file_data in files.items():
                    file_path = SAVE_PATH / filename
                    file_path.write_bytes(file_data)

            elif encoding == 'binary':
                file_name = get_file_name(driver)
                file_path = SAVE_PATH / file_name
                file_path.write_bytes(file_data)
            else:
                print('Unsupported Encoding')
        else:
            print('Failed to initiate transfer')
Esempio n. 10
0
def test_context_manager_calls_open_close_with_exception():
    with mock.patch.object(CIPDriver, 'open') as mock_close, \
         mock.patch.object(CIPDriver, 'close') as mock_open:
        try:
            with CIPDriver(CONNECT_PATH) as driver:
                x = 1 / 0
        except Exception:
            ...
        assert mock_open.called
        assert mock_close.called
Esempio n. 11
0
def stopPlc():
	with CIPDriver('10.0.111.5') as plc:
		data = plc.generic_message(
			service=b'\x07',
			class_code=b'\x24',
			instance=1,
			connected=False,
			unconnected_send=True,
			route_path=True,
			name='STOP_plc' 
		)
		print(data.value)
Esempio n. 12
0
def get_mac_address():
    with CIPDriver('10.10.10.100') as plc:
        response = plc.generic_message(service=Services.get_attribute_single,
                                       class_code=ClassCode.ethernet_link,
                                       instance=1,
                                       attribute=3,
                                       data_type=USINT[6],
                                       connected=False)

        if response:
            return ':'.join(f'{x:0>2x}' for x in response.value)
        else:
            print(f'error getting MAC address - {response.error}')
Esempio n. 13
0
def write_pf525_parameter():
    drive_path = '10.10.10.100/bp/1/enet/192.168.1.55'

    with CIPDriver(drive_path) as drive:
        drive.generic_message(
            service=Services.set_attribute_single,
            class_code=b'\x93',
            instance=41,  # Parameter 41 = Accel Time
            attribute=b'\x09',
            request_data=INT.encode(500),  # = 5 seconds * 100
            connected=False,
            unconnected_send=True,
            route_path=True,
            name='pf525_param')
Esempio n. 14
0
def test_get_module_info_returns_expected_identity_dict():
    EXPECTED_DICT = {
        "vendor": "Rockwell Automation/Allen-Bradley",
        "product_type": "Programmable Logic Controller",
        "product_code": 89,
        "revision": {
            "major": 20,
            "minor": 19
        },
        "status": b"`0",
        "serial": "c00fa09b",
        "product_name": "1769-L23E-QBFC1 LOGIX5323E-QBFC1",
    }

    RESPONSE_BYTES = (
        b"o\x00C\x00\x02\x13\x02\x0b\x00\x00\x00\x00_pycomm_\x00\x00\x00\x00\x00\x00\x00\x00\n"
        b"\x00\x02\x00\x00\x00\x00\x00\xb2\x003\x00\x81\x00\x00\x00\x01\x00\x0e\x00Y\x00\x14\x13"
        b"`0\x9b\xa0\x0f\xc0 1769-L23E-QBFC1 LOGIX5323E-QBFC1")

    driver = CIPDriver(CONNECT_PATH)
    driver._sock = Mocket(RESPONSE_BYTES)
    actual_response = driver.get_module_info(1)
    assert actual_response == EXPECTED_DICT
Esempio n. 15
0
def get_mac_address():
    with CIPDriver('10.10.10.100') as plc:
        response = plc.generic_message(
            service=CommonService.get_attribute_single,
            class_code=ClassCode.ethernet_link,
            instance=1,
            attribute=3,
            data_format=(('MAC', 'SINT[6]'), ),
            connected=False)

        if response:
            return ':'.join(f'{abs(x):0>2x}' for x in response.value['MAC'])
        else:
            print(f'error getting MAC address - {response.error}')
Esempio n. 16
0
def test_get_module_info_returns_expected_identity_dict():
    EXPECTED_DICT = {
        'vendor': 'Rockwell Automation/Allen-Bradley',
        'product_type': 'Programmable Logic Controller',
        'product_code': 89,
        'revision': {
            'major': 20,
            'minor': 19
        },
        'status': b'`0',
        'serial': 'c00fa09b',
        'product_name': '1769-L23E-QBFC1 LOGIX5323E-QBFC1'
    }

    RESPONSE_BYTES = (
        b'o\x00C\x00\x02\x13\x02\x0b\x00\x00\x00\x00_pycomm_\x00\x00\x00\x00\x00\x00\x00\x00\n'
        b'\x00\x02\x00\x00\x00\x00\x00\xb2\x003\x00\x81\x00\x00\x00\x01\x00\x0e\x00Y\x00\x14\x13'
        b'`0\x9b\xa0\x0f\xc0 1769-L23E-QBFC1 LOGIX5323E-QBFC1')

    driver = CIPDriver(CONNECT_PATH)
    driver._sock = Mocket(RESPONSE_BYTES)
    actual_response = driver.get_module_info(1)
    assert actual_response == EXPECTED_DICT
Esempio n. 17
0
def read_pf525_parameter():
    drive_path = '10.10.10.100/bp/1/enet/192.168.1.55'

    with CIPDriver(drive_path) as drive:
        param = drive.generic_message(
            service=Services.get_attribute_single,
            class_code=b'\x93',
            instance=41,  # Parameter 41 = Accel Time
            attribute=b'\x09',
            data_type=INT,
            connected=False,
            unconnected_send=True,
            route_path=True,
            name='pf525_param')
        print(param)
Esempio n. 18
0
def enbt_ok_led_status():
    message_path = '10.10.10.100/bp/2'

    with CIPDriver(message_path) as device:
        data = device.generic_message(
            service=Services.get_attribute_single,
            class_code=b'\x01',  # Values from RA Knowledgebase
            instance=1,  # Values from RA Knowledgebase
            attribute=5,  # Values from RA Knowledgebase
            data_type=INT,
            connected=False,
            unconnected_send=True,
            route_path=True,
            name='OK LED Status')
        # The LED Status is returned as a binary representation on bits 4, 5, 6, and 7. The decimal equivalents are:
        # 0 = Solid Red, 64 = Flashing Red, and 96 = Solid Green. The ENBT/EN2T do not display link lost through the OK LED.
        statuses = {0: 'solid red', 64: 'flashing red', 96: 'solid green'}
        print(statuses.get(data.value), 'unknown')
Esempio n. 19
0
def stratix_power_status():
    message_path = '10.10.10.100/bp/2/enet/192.168.1.1'

    with CIPDriver(message_path) as device:
        data = device.generic_message(
            service=b'\x0e',
            class_code=863,  # use decimal representation of hex class code
            instance=1,
            attribute=8,
            connected=False,
            unconnected_send=True,
            route_path=True,
            data_type=INT,
            name='Power Status')
        # Returns a binary representation of the power status. Bit 0 is PWR A, Bit 1 is PWR B. If 1, power is applied. If 0, power is off.
        pwr_a = 'on' if data.value & 0b_1 else 'off'
        pwr_b = 'on' if data.value & 0b_10 else 'off'
        print(f'PWR A: {pwr_a}, PWR B: {pwr_b}')
Esempio n. 20
0
def ip_config():
    message_path = '10.10.10.100/bp/2'

    with CIPDriver(message_path) as plc:  # L85
        data = plc.generic_message(service=b'\x0e',
                                   class_code=b'\xf5',
                                   instance=1,
                                   attribute=3,
                                   connected=False,
                                   unconnected_send=True,
                                   route_path=True,
                                   data_type=INT,
                                   name='IP_config')

        statuses = {0b_0000: 'static', 0b_0001: 'BOOTP', 0b_0010: 'DHCP'}

        ip_status = data.value & 0b_1111  # only need the first 4 bits
        print(statuses.get(ip_status, 'unknown'))
Esempio n. 21
0
def getIPConfig():
    message_path = '10.0.111.5'

    with CIPDriver(message_path) as plc:  # L85
        data = plc.generic_message(
            service=b'\x0e',
            class_code=b'\xf5',
            instance=1,
            attribute=3,
            connected=False,
            unconnected_send=True,
            route_path=True,
            name='IP_config'
        )

        statuses = {
            0b_0000: 'static',
            0b_0001: 'BOOTP',
            0b_0010: 'DHCP'
        }
        print(data.value)
Esempio n. 22
0
def test_close_raises_commerror_on_any_exception(mock_method, exception):
    """Raise a CommError if any CIPDriver methods raise exception.
    
    There are two CIPDriver methods called within close:
        CIPDriver._forward_close()
        CIPDriver._un_register_session()

    If those internal methods change, this test will break. I think
    that's acceptable and any changes to this method should make the
    author very aware that they have changed this method.
    """
    with mock.patch.object(CIPDriver, mock_method) as mock_method:
        mock_method.side_effect = exception
        with pytest.raises(CommError):
            driver = CIPDriver(CONNECT_PATH)
            driver._target_is_connected = True
            driver._session = 1
            driver.close()
Esempio n. 23
0
def test__forward_open_returns_true_if_already_connected():
    driver = CIPDriver(CONNECT_PATH)
    driver._target_is_connected = True
    assert driver._forward_open()
Esempio n. 24
0
def test_open_returns_false_if_register_session_falsy():
    driver = CIPDriver(CONNECT_PATH)
    driver._sock = Mocket()
    assert not driver.open()
Esempio n. 25
0
def test_open_raises_commerror_on_connect_fail():
    with mock.patch.object(Socket, 'connect') as mock_connect:
        mock_connect.side_effect = Exception
        driver = CIPDriver(CONNECT_PATH)
        with pytest.raises(CommError):
            driver.open()
Esempio n. 26
0
def test_open_returns_true_if_register_session_truthy():
    with mock.patch.object(CIPDriver, '_register_session') as mock_register:
        mock_register.return_value = 1
        driver = CIPDriver(CONNECT_PATH)
        driver._sock = Mocket()
        assert driver.open()
Esempio n. 27
0
def test__register_session_returns_configured_session(conf_session):
    driver = CIPDriver(CONNECT_PATH)
    driver._sock = Mocket(bytes(4) + UDINT.encode(conf_session) + bytes(20))
    assert conf_session == driver._register_session()
Esempio n. 28
0
def test__register_session_returns_none_if_no_response():
    driver = CIPDriver(CONNECT_PATH)
    driver._sock = Mocket()
    assert driver._register_session() is None
Esempio n. 29
0
def test__forward_open_returns_false_if_falsy_response():
    driver = CIPDriver(CONNECT_PATH)
    driver._sock = Mocket()
    driver._session = 1
    assert not driver._forward_open()
Esempio n. 30
0
def test__forward_open_raises_commerror_if_session_is_zero():
    driver = CIPDriver(CONNECT_PATH)
    with pytest.raises(CommError):
        driver._forward_open()