RoanBrand / MQTT-Siemens-S7-300

MQTT library block written in Siemens SCL for S7-300 PLC with CP343-1
89 stars 47 forks source link
mqtt mqtt-library plc siemens siemens-s7-plcs

MQTT-Siemens-S7-300

MQTT library block written in SCL for S7-300 with internal (PN) or external (CP) Ethernet.

This started as a port of knolleary's MQTT library for Arduino & ESP8266. The implementation is following the MQtt v3.1.1 protocol documentation (http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html)

Main functionallity complete, still work in Progress!

Purpose and Possibilities

MQTT is a popular communications protocol in the IoT space. Its demand on most types of networks and CPUs make it a good option for M2M applications. MQTT devices can easily be utilized to send a message anywhere in the world.

What does this mean for PLCs & Industrial Automation?

MQTT will enable a PLC to connect to the cloud without using proprietary hardware or protocols. PLC programmers can use it to build customized programs that send info to a web server, log plant data, and communicate with any other MQTT client device. Developers can use it to build customized dashboards (physical, website, or mobile device), providing valuable data for analytics and business. MQTT enabled IO could serve as an inexpensive alternative for the PLC. (although not recommended for mission critical IO and for safety reasons)

Current Test Scenario:

At this time, this code has been successfully tested on:

The PLC is connected to a Mosquitto MQtt broker. All main functionallity has been testet: connect, disconnect, subscribe, unsubscribe, ping, publish. I am locally connecting to a Mosquitto broker.

Currently Limitations:

Todo:

Requirements

It should work with most S7-300/400 CPU's. This code is written in Step7 SCL v5.3 SP1. It probably needs modification for it to compile in TIA.

Setup the Step7 project

You need to add the following Objects Library blocks to your project:

Only needed for internal ethernet support (PN): Library: Standard Library -> Communication Blocks -> Blocks

Compiling the project

Block numbers generation

There are two ways to generate the Block numbers required by the project. Block numbers can be generated automatically or they can be manually setup in the projects Symbols table. Block number auto generation can be configured by setting the “Create block numbers automatically” option in the Options -> Customize menu of the SCL editor, in the “General” tab the “Create block numbers automatically” option must be set. If block numbers must be set manually, open the “S7 Symbols.xlsx” document in the Support folder, set the block numbers according to your requirements and copy&paste them into the S7 projects Symbols table.

Compiling the S7 MQTT project

There are two Makefiles, please choose the right one for the Ethernet requirements (ProfiNet, CP) of the project:

Imporant: You must call the MQTT function block in your OB1 program loop.

Example programm

Optional: You may compile the MQTT_Example.scl

Network Configuration

The MQTT FB can use the internal Ethernet adapter of a CPU (PN, choose MQTT_Main_PN.scl) or an external Ethernet adapter (CP, choose MQTT_Main_CP.scl).

Remarks for internal Ethernet (PN) adapter configuration:

Setup memory footprint

Setting up buffers

To reduce the memory usage of the MQtt DBs you can set the receive and transmit buffer sizes.

Keep in mind: data from tcpRecBuf is transfered to buffer and also data from buffer is tranfered to tcpSendBuf within the Code. So match the sizes appropriately.

Check connection status

You can check the connection status by monitoring two Flags in mqttData DB:

mqttData.ethTCPConnected : this Boolean will show you the state of the TCP connection to the broker

mqttData._state : will show you the connection status of the MQtt connection to the broker. Check for value > 0 to check if MQTT is connected. I recommend to check this status before trying to send a message.

mqttData.mqttErrorCode : will hold the last MQtt error code

mqttData.tcp_sendBufferFull : will be true if the send buffer is full. Important: this also indicates that the last message could not be added to the send buffer, the last message therefore was discarded. To avoid problems with the send buffer, give it an appropriate size to hold multiple messages and also only send if mqttData._state > 0.

Example

Included is an example application function block (FB70) that is typically called from OB1. Inputs for this block can trigger a MQTT broker connect, publish a message or subscribe to a MQTT channel.

There is also some example code for calculating a payload CRC to check the data integrity. The used CRC_GEN function can be found in the oscat.de PLC library.

Notes

Porting C++ to Siemens SCL has taught many differences between systems. Differences include:

One reason for this is a PLC is a real-time system. A consequence is that the entire program code, from the first to last line, must complete in a certain amount of time. (Typically <10ms) The workaround I make is using a FB with a state machine that can wait for a procedure to finish before moving on.

After working with SCL for a while it feels that the language is primitive in many ways in comparison with most PC languages. I realise that some of it is because of program limitation for safety and resource conservation, but general program principles like DRY, OOP, etc. are sometimes difficult to achieve if not impossible.

Another annoying difference is the idea of having symbol entries for symbolic block names. On one side I want to refactor and break behaviour up in more functions like in general programming. But in Siemens I don't want to create a new symbol entry for each FC that I make. Also, this is probably not encouraged in PLC programming anyway as it increases the maximum size of the call stack in every scan cycle and increases the scan time. This makes it difficult to make small sized program code that is also performant.

Furthermore, the low-level programming and memory limitation reminds of microcontroller programming.