Publish AI, ML & data-science insights to a global community of data professionals.

REST APIs on Industrial PLCs

Expand the capabilities of a PLC to perform virtually any task

Communication to a REST API, Image by Author
Communication to a REST API, Image by Author

Introduction

APIs allow for easy interfacing between two different applications and in this article a basic implementation of a Python REST API¹ will be used to manage various SQL commands from a PLC².

In this example, data will be sampled from a network of Sigma-7 Servo Drives that are connected to MP3300iec Controllers. The data will be used for training and evaluating an Anomaly Detection³ model that will be used across the network of similarly configured machines. For this reason, a good design would be to have one central server communicating with all of these machines, storing all of the data, calculating the weights of the model, and distributing the weights back to the controllers in real-time.

Motivation

By communicating with a Python Application via a REST API, anything that is not possible to run on a PLC is now able to run on a local server and return the result to the PLC. This allows for expensive computational processes to run alongside the Controller in real-time. For example, a large Machine Learning model with several hundred thousand or million parameters will likely cause a WatchDog error or cpu load issue if run on a Controller alongside the other processes and tasks. There are two immediate solutions:

  1. Reduce the Machine Learning model size
  2. Run the computation on a different piece of hardware

In some cases option 1 will work just fine, however, the model accuracy will likely suffer. Some applications may be possible with the loss in accuracy, but others that demand higher accuracy will likely require option 2.

In addition to distributing the computational load to another device, the REST API is useful for performing actions not typical to controllers. Some examples may include: tracking orders or inventory, getting information from a third party application, or communicating with an external network.

Although it may be possible to communicate with a third party application directly from the controller, it is significantly easier to do so with with prebuilt libraries and repositories from the authors of the given application. With the popularity of Python and other modern programming languages, many libraries and tools exist to do the heavy lifting for you. Using a REST API allows you to do so, and any additional custom operations required by the process.

REST API

The API will run on a server located within the local network associated with all of the controllers. Python’s Flask module is used to create all of the endpoints used for the data handling. The first endpoint defined will be used to add a data point to the database and is shown below:

@app.route('/add_row', methods=['POST']) def add_row(): row_data = request.data if insert_sql_row(data): return json.dumps({'statusCode': 200, 'data': 'Success'}) else: return json.dumps({'statusCode': 400, 'data': 'Error'})
def insert_sql_row(row_data) -> bool: try: database = mysql.connector.connect( host = 'localhost', user = 'admin', password = 'password' ) cursor = database.cursor()
 sql_statement = 'INSERT INTO table_name VALUES (' for value in row_data: sql_statement = f'{sql_statement},{value}' sql_statement = f'{sql_statement})'
 cursor.execute(sql_statement) database.commit() cursor.close() database.close() return True except: return False

A few key items in the code above:

  • /add_row endpoint: this is the endpoint that will be used when the controller wishes to add a row of data to the database.
  • request.get_data(): this returns the data associated with the request that contains the row of sampled values to be entered into the database among other pieces of information relevant to the network request
  • mysql.connector: this is the module used to connect and query the SQL database.

The next endpoint defined will be used to retrieve the Anomaly Detection model from the database. The model weights will be stored in a different table and this is reflected in the code below:

@app.route('/retrieve_model', methods=['GET']) def retrieve_model(): model_id = request.data return json.dumps( {'statusCode': 200, 'data': str(retrieve_sql_row(model_id)) } )
def retrieve_sql_row(model_id): try: database = mysql.connector.connect( host = 'localhost', user = 'admin', password = 'password' ) cursor = database.cursor() cursor.execute(f'SELECT * FROM ml_model_table WHERE model_id="{model_id}"' ) row = cursor.fetchone() cursor.close() database.close() return row if row else [] except: return []

Communicating with the API

The Controllers communicate with the API via HTTP requests that are sent through TCP sockets. For a basic GET command that will return the Anomaly Detection model weights to the client, the following string can be used:

GET /retrieve_model HTTP/1.1

The first part of the string (‘GET’) indicates the type of REST method that is being requested, the second part of the string _(‘/retrievemodel’) indicates the endpoint being requested, and the last part of the string (‘HTTP/1.1’) specifies the HTTP protocol version.

When using the data storage endpoint created above, the above command would be modified to the following:

POST /add_row HTTP/1.1

On the PLC programming side, a custom Function Block has been created that handles all of the pre and post processing required to issue these commands. It is shown below:

Function Block used to make REST requests, Image by Author
Function Block used to make REST requests, Image by Author

The ‘REST_API_1’ Function Block has the following inputs:

  • Execute: A boolean that sends the command and awaits the response
  • Port: This is the port number of the server that the request is being sent to
  • IPAddress: This is the IP address of the server that the request is being sent to
  • LocalIP: This is the assigned IP address of the device making the request.
  • CommandType: This is the type of REST command being requested.
  • Data: This is a structure that contains all of the data that will be attached to the request

A singular output ‘ReceivedString’ exists. This is a string of the server response. In this example, it will be a JSON structured response in the form:

{'statusCode': 200, 'data': 'Success'}

Example

The example begins by running the Flask server that will host the REST API. The code from the "REST API" section above is used for this example, and the log shows that the server is running:

Output log of the Flask Server Initializing, Image by Author
Output log of the Flask Server Initializing, Image by Author

In the PLC program, the ‘Execute’ boolean is enabled on the ‘REST_API_1’ Function block, containing the following inputs:

  • Port = 5000
  • IPAddress = 192.168.1.71
  • LocalIP = 192.168.207.35
  • CommandType = ‘GET’
  • Data = {‘endpoint’ : ‘/retrieve_model’, ‘model_id’ : ‘AnomalyS7’}

Once the server responds to the request, the following output is received by the ‘ReceivedString’ output:

{'statusCode': 200, 'data': [0.0291, 0.1253. 0.2843, 0.0112, 0.0895, 0.2001, 0.0013, 0.0984]}

Now the controller has the necessary weights to run Anomaly Detection with the updated Machine Learning model weights from the server.

Conclusion

Using a REST API is an easy way to expand the capabilities of a PLC. It allows for the controller to request almost any type of process and offload computation to another device. Using Python’s Flask is one of the simplest and easiest ways of achieving this.

References

[1] Wikimedia Foundation. (2022, May 22). Representational state transfer. Wikipedia. Retrieved May 25, 2022, from https://en.wikipedia.org/wiki/Representational_state_transfer

[2] Wikimedia Foundation. (2022, May 22). Programmable logic controller. Wikipedia. Retrieved May 25, 2022, from https://en.wikipedia.org/wiki/Programmable_logic_controller

[3] Lebiedzinski, P. (2021, November 12). Anomaly Detection on Servo Drives. Medium. Retrieved May 12, 2022, from https://towardsdatascience.com/a-single-number-metric-for-evaluating-object-detection-models-c97f4a98616d.


Towards Data Science is a community publication. Submit your insights to reach our global audience and earn through the TDS Author Payment Program.

Write for TDS

Related Articles