This repository is deprecated; please follow the main search page or use the ‘Related code repos’ widget on the right side of the current page.

Cisco IOx application example to use Modbus TCP on a Cisco IR1101 with Python

The purpose of this sample code is to showcase how you can very simply access Modbus TCP Programmable Logic Controllers (PLC) from a Python 3 environment and run it on Cisco IOx.

Our aim in this case is simply to trigger a few Modbus coil registers on and off and have some fun doing the visual effect of Kitt in Knight Rider, on a PLC!

Cisco IOx is an execution and hosting environment and in this case we will build an application package for the Cisco IR1101 which is a ARM-based platform. For this reason we will need to include QEMU for cross-compilation on an Intel x86_64 platform. For more information on how to set-up your machine check "Build and Deploy a Docker IOx Package for the IR1101 ARM Architecture".

This sample is using Python 3 along with the pyModbusTCP library which is an extremely compact implementation.

Kitt

Use Case Description

In this code sample we are going to simulate Kitt, with the back and forth light flashing on a PLC. This is not very useful per se, however the purpose is to show how to set this up so you can embark on much more useful use cases.

Prerequisites

  • You need a PLC or anything that can act as a Modbus Master. In this case I have used a PLC from B&R which provides Modbus TCP data. Note that this PLC requires programming the Modbus table with B&R "Automation Studio", and once this step is done then you can view the Modbus registers to use.
  • You need a device with Cisco IOx. In this case I have used a Cisco Industrial Router IR1101, but you could also use Cisco Industrial Ethernet IE3400 with minimal or no change. The gateway need to be configured to give access to your containers to the local network or wherever is your PLC.
  • You need a build machine with internet access and Docker, ioxclient, and git.

Getting the IR1101 ready with IOx

Although covered in the Cisco IOS-XE documentation, here's a quick run down on how to set up IOx networking. On the IR1101 all IOx containers will be presented as being connected to interface VirtualPortGroup0. We will use a dynamic DHCP pool to assign containers an IP address and Network Address Translation (NAT) to masquerade the IP traffic.

You need to get access to the router console to enter those commands.

The external, public interface will be the main GigabitEthernet0/0/0 port. It will take it's IP address from an external DHCP server, but of course you can also assign a static IP address. Here is an example on what to do on the router console for DHCP:

interface GigabitEthernet0/0/0
 ip address dhcp
 ip nat outside

Then configure the VirtualPortGroup0 interface with an IP address and as NAT inside. All containers will appear as being connected to that network:

 interface VirtualPortGroup0
 ip address 192.168.1.1 255.255.255.0
 ip nat inside

For our containers to receive an IP address, we then need to also configure a DHCP pool:

ip dhcp pool iox
 network 192.168.1.0 255.255.255.0
 default-router 192.168.1.1
 dns-server 8.8.8.8

You can also use a static IP address for the container during the activation phase, and skip the DHCP server configuration. This will allow the container to always come back with the same IP address which may be interesting when doing port forwarding. When not doing port forwarding the DHCP method is the most simple one.

Since this container also need access to the external network where our PLC is configured, we also need to configure Network Address Translation (NAT) to "hide" our private IP address as if it was coming from the router's public interface. Here's how to do that:

ip access-list extended 100
    10 permit ip 192.168.1.0 0.0.0.255 any

ip nat inside source list 100 interface GigabitEthernet0/0/0 overload

Installation

On your build machine start by cloning the repo with:

  git clone https://github.com/etychon/iox-ir1101-modbustcp-br-py

In the start.py main program, change the base address on your Coil address. This information is coming from the Modbus Exchange Table which describes the type, size and address of the registers.

In my case the table was generated by the B&R "Automation Studio" software and the output was like so:

modbus

My Digital Output module in slot 5 has a base address of 0x0008 and six output, with one bit per output. We will then configure the register and number of output in the start.py program by changing to the base address r_addr_hex to 0x0008 and the maximum register number to 5 (6 registers from 0 to 5, so maximum is 5).

Edit the start.py script to customise it for your specific PLC configuration:

  r_addr_hex = "0008"
  max_registers = 5;

As an exercise you can make those parameters configurable through the package_config.ini configuration file. Currently it is being used only to configure the PLC IP address after the application activation and before execution, so it will be used to configure the target IP address of your PLC.

This process of using a package_config.ini file to configure parameters is called "bootstrapping" in Cisco IOx allows application parameters to be changed without touching the container itself.

For example in this case the package_config.ini file contains an IP address that can be changed to match your PLC IP address. You can edit the package_config.ini directly or through IOx activation:

[PLC]
IP_Address:192.168.2.167

After the IP address has been changed and before going further you can check if this runs properly on your PLC with:

run

You can now proceed with building your Docker image:

docker build -t iox-ir1101-modbustcp-br-py .

Similarly you can validate that the image runs well as a Docker container with:

docker run iox-ir1101-modbustcp-br-py

Note that when you run the start.py script it runs with your local x86 Python interpreter, whereas in the Docker container it runs as an emulated ARM Python interpreter. This abstraction is provided in the container by QEMU.

Now is the time to package this image as an IOx application using Cisco ioxclient utility, which takes additional information from the resource descriptor file package.yaml. This file describes the target architecture, network and resource requirements, description and version.

ioxclient docker package iox-ir1101-modbustcp-br-py . -n iox-ir1101-modbustcp-br-py --use-targz

Your Cisco IOx application is now in the current directory and called iox-ir1101-modbustcp-br-py.tar.gz.

Usage

Log in to the IR1101 Local Manager WebUI by logging in to the main router WebUI, then navigate to Configuration > Services > IOx to log in to the Cisco IOx Local Manager which is using the same credentials as the main router WebUI.

Deploy the application like so:

iox-deploy

Then activate and optionally configure IP address like so:

activate and start

Your application is now running in Cisco IOx and you should see your PLC running Kitt's Knight Rider effect. Here's how it looks like on mine:

running

Getting help

If you have questions, concerns, bug reports, etc., please create an issue against this repository.

Getting involved

This section should detail why people should get involved and describe key areas you are currently focusing on; e.g., trying to get feedback on features, fixing certain bugs, building important pieces, etc. Include information on how to setup a development environment if different from general installation instructions.

General instructions on how to contribute should be stated with a link to CONTRIBUTING file.


Copyright (c) 2020 Cisco Systems, Inc. and/or its affiliates

View code on GitHub
  • Owner

  • Contributors

    +1Github contributor
  • Categories

  • Products

    IOS XE
  • Programming Languages

    Python
  • License

    MIT License

Code Exchange Community

Get help, share code, and collaborate with other developers in the Code Exchange community.View Community
Disclaimer:
Cisco provides Code Exchange for convenience and informational purposes only, with no support of any kind. This page contains information and links from third-party websites that are governed by their own separate terms. Reference to a project or contributor on this page does not imply any affiliation with or endorsement by Cisco.