Skip to content

Latest commit

 

History

History
481 lines (359 loc) · 24.3 KB

MqttClient_Technical_Details.md

File metadata and controls

481 lines (359 loc) · 24.3 KB

PLCnext Technology - MQTT Client

Date Version
06.12.2019 1.2.0

IMPORTANT NOTE

Installing or uninstalling this Function Extension will automatically restart the PLC.

Description

MQTT GDS Connector is a PLCnext Technology component that exchanges data between Global Data Space (GDS) ports and MQTT server topics.

PLCnext Engineer Port Example

The component is configured with the file `mqtt_gds.settings.json` which is stored locally on the device.
{ "brokers":[{
    "host": "tcp://test.mosquitto.org:1883",
    "client_name": "MQTT_Test_App",
	"status_port": "Arp.Plc.Eclr/TestBench1.MQTT_Broker_Status",
    "connect_options":{
      "will_options":{
        "topic": "last_will_topic",
        "payload": "auf wiedersehen"
      }
    },
    "publish_on_change": true,
    "cycle_count_port": "Arp.Plc.Eclr/TestBench1.CycleCount",
    "publish_data":[{
      "port"   : "Arp.Plc.Eclr/TestBench1.PubLoadTestBool",
      "qos": 0,
      "retained": false,
      "topics" :[
        "LoadTestBool"
      ]
    }
],
    "subscribe_data":[{
      "topic" : "LoadTestBool",
      "ports" :[
        "Arp.Plc.Eclr/TestBench1.SubLoadTestBool"
      ]
    }
]
  }]
}

The entries in this file must conform to the defined JSON schema (please refer for more details the "configuration reference" section below).

Note: Every invalid configuration (invalid schema or missing mandatory field) leads to a stop of the app. Debug information will appear in the Output.log file of the PLC: /opt/plcnext/logs/Output.log

Requirements

  • AXC F 2152 with minimum firmware version 2020.0
  • Valid account for the PLCnext Store with payment credentials (not needed for the trial version)
  • The PLCnext Control must be connected to the internet and must be registered in the PLCnext Store

Features

  • The MQTT Client app is compatible with MQTT version 3.1 and 3.1.1
  • Support of TCP and Websockets over an unencrypted or an encrypted (SSL/TLS) connection
  • Automatic reconnect to the MQTT Broker
  • Easy handling due to GDS port mapping, no further configuration effort
  • Publish data on change or, alternatively, cyclic update of Publish Topics, individually adjustable (minimum 500ms)
  • Support of the following data types* (Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64, Real32, Real64, String**, DateTime)

*The named data types are C++ types. Please refer the PLCnext Technology Handbook (available in the PLCnext Community) for the corresponding IEC 61131-3 or Matlab Simulink data types.
**String data is always published with a terminating NULL character. When subscribing to String data, incoming message payloads must always include a terminating NULL character.

Quick start

This example exchanges data between a PLC (MQTT Client) and an iPhone* or iPad* (both MQTT Clients) via a public MQTT broker, over an unencrypted connection. It requires a PLC that is connected to the internet, and a PC with access to both the PLC and the internet. For this example, the PC must have PLCnext Engineer software installed.

*This is only an example. There are many other free MQTT Test Clients for Android, Windows or Linux available

  1. Make sure that your AXC F 2152 runs on firmware version >=2019.9, and that it has access to the Internet.
  2. Register for a user account and authorize your AXC F 2152 in the PLCnext Store.
  3. Deploy the app via the PLCnext Store.
  4. Create an IEC 61131 project in PLCnext Engineer with the following configuration:
  • one AXC F 2152 PLC with the template version >=2019.0 LTS
  • one program called "Main"
  • one program OUT port called "PubMessage" of STRING type
  • one program IN port called "SubMessage" of STRING type
  • one instance of the Main program, called "MainInstance"
  1. Download the PLCnext Engineer project to the PLC.

  2. Go online to the PLC and change the value of the "PubMessage" variable in the "MainInstance" program instance.

  3. Install the MQTTool app on an iPhone or iPad.

  4. Open the MQTTool app and connect to the public Mosquitto test broker (test.mosquitto.org, port 1883).

  5. On a PC, create a text file named mqtt_gds.settings.json, containing the following configuration:

    {
      "brokers":[{
        "host": "tcp://test.mosquitto.org:1883",
        "client_name": "MyPLCnext",
        "connect_options":{
          "will_options":{
            "topic": "last_will_topic",
            "payload": "auf wiedersehen"
          }
        },
        "publish_data":[{
          "port"   : "Arp.Plc.Eclr/MainInstance.PubMessage",
          "qos"    : 0,
          "retained": false,
          "period": 10,
          "topics" :[
            "MyPubTopic"
          ]
        }],
        "subscribe_data":[{
          "topic" : "MySubTopic",
          "ports" :[
            "Arp.Plc.Eclr/MainInstance.SubMessage"
          ]
        }]
      }]
    }

    In the configuration file, change the client_name property to a value that is likely to be unique on a public server.

    Change the publish and subscribe topic properties to values that are likely to be unique on a public server.

  6. Using WinSCP (Windows) or scp (Linux), copy the mqtt_gds.settings.json file to the following directory on the PLC: /opt/plcnext/projects/MqttClient/. Create this directory on the PLC if it does not exist already.

    The default login credentials for the PLC are:

    • User name : admin
    • Password : <printed on the PLC housing>
  7. Restart the PLC.

  8. In the MQTTool app on the iPhone or iPad, subscribe to the topic name that was entered in the publish_data section of the configuration file (e.g. "MyPubTopic").

  9. The messages received on the iPhone or iPad now show the value of the PubMessage variable in the PLC.

  10. On the iPhone or iPad, publish a message to the topic that was entered in the subscribe_data section of the configuration file (e.g. "MySubTopic"). This message now appears as the value of the SubMessage variable in the PLC.

"Publish on change" vs "Publish cyclically"

The app can be configured to publish port data using one of two methods:

  1. Publish data only when the value of the data changes.

  2. Publish data on a fixed period, regardless of whether there has been any change to the value of the data.

The first of these options is suitable for publishing data that does not change regularly. This may save on data transmission costs (e.g. on mobile data networks). This option is also suitable for event data, which may only need to be published once when the event occurs.

The second option provides behaviour that is similar to that of the Proficloud Time Series Data (TSD) service, where data is published on a fixed cycle regardless of whether the data has changed.

Note that when publishing "on change", changes are detected based on data samples taken every 500 ms (approximately). If the user wishes to publish data on a single topic at a faster rate than this, then the user must buffer the data (e.g. in an array), and feed the data into the published Port variable(s) at a rate not greater than the data sample rate. In order to assist with this, the MQTT Client app provides a cycle_count_port parameter (see configuration section below). If the cycle_count_port is specified in the configuration file, then the value of the cycle_count_port variable will be incremented by the MQTT Client app each time a data sample is taken for change detection. This variable can then be used as a "clock" for feeding data into the Publish ports. Note that the cycle_count_port variable will be incremented each time a data sample is taken, regardless of whether any change to the publish data is detected.

Configuration reference

The MQTT GDS Client is configured with the file mqtt_gds.settings.json. This file must be located in the following directory on the PLC:

/opt/plcnext/projects/MqttClient/

This directory must be created on the PLC if it does not exist already.

For encrypted connections, a server certificate, client certificate and client private key may be required. These files should be copied to the PLC using WinSCP (Windows) or scp (Linux). The user is free to place these files anywhere on the PLC file system. The absolute path to these files must then be specified in the relevant ssl_options configuration fields.

All changes to the configuration will only take effect after a restart of the PLC.

Configuration schema

The configuration file mqtt_gds.settings.json must comply with the JSON schema defined in the file mqtt_gds.schema.json. This schema file must be located in the following directory on the PLC:

/opt/plcnext/apps/60002172000048/

Note: Every invalid configuration (invalid configuration or missing mandatory field) leads to a stop of the app. Debug information will appear in the Output.log file of the PLC: /opt/plcnext/logs/Output.log


Broker properties

A valid configuration consists of an array of MQTT Broker objects. Each broker object represents one MQTT client-broker connection.

Note: The MQTT Client version 1.x only supports one MQTT Broker connection.

Name Required JSON type Description
host Yes string The address of the server to connect to, specified as a URI.1
clientId Yes string A client identifier that is unique on the server being connected to.
status_port No string The name of a boolean GDS port that will receive the client connection status.2
connect_options Yes object The connection options. See table below.
publish_on_change No boolean Publish all variables on change (false/default: publish on a fixed period).3
cycle_count_port No string The name of a UInt64 GDS port which can receive a monotonically increasing integer.2,4.
publish_data No array of objects MQTT publish information. See table below.
subscribe_data No array of objects MQTT subscribe information. See table below.

Note:

  1. The host must be specified in the following format:

    protocol://host:port

    ... where protocol must be tcp, ssl, ws or wss. If nothing is specified, tcp is assumed. For host, you can specify either an IP address or a domain name.

  2. Ports on PLCnext Engineer programs must be specified in the following format:

    Arp.Plc.Eclr/ProgramInstance.PortName

    ... where ProgramInstance must be the name of the program instance in the PLCnext Engineer project, and PortName must the name of a port variable defined in that program.

  3. The publish_on_change switch applies to all published variables, i.e. all variables must be published either on change, or on fixed period(s). The maximum publish frequency remains at 2 Hz (i.e. 500 ms period).

  4. To assist with the "Publish On Change" feature, users can configure a GDS port to receive an integer that increments after each publish cycle. This cycle_count_port value can be used as a clock to feed messages into GDS variables from a buffer, if necessary.


connect_options

Name Required JSON type Default value Description
username No string NULL The user name to use for the connection.
password No string NULL The password to use for the connection.
mqtt_version No integer 0 The version of MQTT to be used on the connect.1
will_options Yes object The LWT options to use for the connection. See table below.
ssl_options No object The SSL options to use for the connection. See table below.

Note:

  1. mqtt_version:
    • 0 = default: start with 3.1.1, and if that fails, fall back to 3.1
    • 3 = only try version 3.1
    • 4 = only try version 3.1.1
  2. LWT = Last Will Topic

will_options

Name Required JSON type Description
topic Yes string The LWT message is published to the this topic.
payload Yes string The message that is published to the Will Topic.
qos No integer The message Quality of Service.
retained No boolean Tell the broker to keep the LWT message after sent to subscribers.

ssl_options

The ssl option is only needed when encrypted ssl communication is used. Depending on the MQTT Broker policies, different configurations may be needed.

Name Required JSON type Description
trust_store Yes string The filename containing the public digital certificates trusted by the client.
key_store No string The filename containing the public certificate chain of the client.
private_key No string The filename containing the client's private key.
private_key_password No string The password to load the client's privateKey (if encrypted).
enabled_cipher_suites No string The list of cipher suites that the client will present to the server during the SSL handshake.
enable_server_cert_auth No boolean Enable verification of the server certificate.

Broker configuration example

The following examples show two broker configurations. One is a simple unencrypted connection to the Mosquitto MQTT test broker and the other is an encrypted connection.

{ "brokers":[{
 "host": "tcp://test.mosquitto.org:1883",
 "client_name": "MQTT_Test_App",
 "status_port": "Arp.Plc.Eclr/TestBench1.MQTT_Broker_Status",
 "connect_options":{
   "will_options":{
     "topic": "last_will_topic",
     "payload": "auf wiedersehen"
   }
}]
}

Configuration example for an unencrypted connection

{ "brokers":[{
 "host": "ssl://test.mosquitto.org:8883",
 "client_name": "MQTT_Test_App",
 "status_port": "Arp.Plc.Eclr/TestBench1.MQTT_Broker_Status",
 "connect_options":{
   "will_options":{
     "topic": "last_will_topic",
     "payload": "auf wiedersehen"
   },
 "ssl_options":
 {
         "trust_store": "/opt/plcnext/projects/MqttClient/mosquitto.org.crt",
         "key_store": "/opt/plcnext/projects/MqttClient/client.crt",
         "private_key": "/opt/plcnext/projects/MqttClient/client.key",
         "private_key_password": "dont_tell",
         "enabled_cipher_suites": "",
         "enable_server_cert_auth": true

    }
 }
}]
}

Configuration example for an encrypted connection


publish_data

Publish_data must be an array of objects with the following properties:

Name Required JSON type Description
port Yes string The 'OUT' port from which data will be published1.
period No integer The publish frequency in seconds (max 86,400). If not specified, period=500ms.
qos Yes integer The message Quality of Service2.
retained Yes boolean Tell the broker to keep messages after send to subscribers3.
topics Yes array of strings Message are published to all these topics.

Note:

  1. Ports published from PLCnext Engineer projects must be specified in the following format:

    Arp.Plc.Eclr/ProgramInstance.PortName

    ... where ProgramInstance must be the name of the program instance in the PLCnext Engineer project, and PortName must the name of an OUT port variable defined in that program.

  2. The MQTT app version 1.x only supports QoS 0

  3. The MQTT app version 1.x does not support 'retained'.

publish_data configuration example

The following example shows a valid configuration.

Note: Make sure that the assigned GDS ports exist and that the data type is correct. An incorrect configuration will prevent the app from starting.

 "publish_on_change": true,
 "cycle_count_port": "Arp.Plc.Eclr/TestBench1.CycleCount",
 "publish_data":[{
   "port"   : "Arp.Plc.Eclr/TestBench1.PubLoadTestBool",
   "qos": 0,
   "retained": false,
   "topics" :[
     "LoadTestBool"
   ]
 }

subscribe_data

subscribe_data must be an array of objects with the following properties:

Name Required JSON type Description
topic Yes string This topic is subscribed Message are published to all these topics.
ports Yes array of strings The 'IN' ports to which subscription data will be written1.

Note:

  1. Ports in PLCnext Engineer projects that subscribe to MQTT topics must be specified in the following format:

    Arp.Plc.Eclr/ProgramInstance.PortName

    ... where ProgramInstance must be the name of the program instance in the PLCnext Engineer project, and PortName must the name of an IN port variable defined in that program.

subscribe_data configuration example

The following example shows a valid configuration.

Note: Make sure that the assigned GDS port exists and that the data type is correct. An incorrect configruation will prevent the app from starting.

"subscribe_data":[{
   "topic" : "LoadTestBool",
   "ports" :[
     "Arp.Plc.Eclr/TestBench1.SubLoadTestBool"
   ]
 }

Configuration examples

A complete configuration example can be found here.
Remember that your own configuration file must always be named mqtt_gds.settings.json.

Note on operation in different PLC states

When the PLC goes into "Stop" mode, all PLCnext task processing will be suspended, but the MQTT Client will continue to run. GDS variables will continue to be read and written by the MQTT Client app. This is by design, because any or all GDS variables can be associated with processes that are not running in PLCnext tasks, e.g. other Function Extensions, or other Runtime applications.

Known issues and limitations

  • Only one client, and one concurrent server connection, is currently supported
  • When the network connection to the broker is lost and restored, and a manual or automatic reconnect is triggered, the MQTT Client will block for precisely the number of milliseconds specified by the broker "timeout" property (default: 300 seconds).
  • Complex data types (including Arrays and Structures) are not currently supported.
  • Only QoS 0 is supported
  • The app checks the assigned GDS port in terms of availability and type during the start-up process. Any changes to GDS ports (delete, rename or type) during operation (e.g. if a modified PLCnext Engineer project is downloaded without stopping the PLC) can lead to an undefined behaviour!
  • When the PLC goes into "Stop" mode, all PLCnext task processing will be suspended, but the MQTT Client will continue to run. GDS variables will continue to be read and written by the MQTT Client app. This is by design, because any or all GDS variables can be associated with processes that are not running in PLCnext tasks, e.g. other Function Extensions, or other Runtime applications.

Error handling

The app logs the complete startup, connection and error history into the Output.log file (/opt/plcnext/logs/Output.log) of the PLC which gives the user a reliable indication of the current state of the app. In addition, a status port can be configured (please refer the chapter 'broker properties'). The value true indicates that the app was successfully started (configuration correct) and that connection to the configured MQTT Broker could be established. The values goes to false when the app could not be started (wrong configuration) or when the connection to the MQTT Broker could not be established or is interrupted.

Note: Phoenix Contact strongly recommend the usage of the "status_port".

Diagnostic Log

This chapter explains the most important diagnostic messages and is intended to support troubleshooting the MQTT app.

All diagnostics are printed in the output.log file (/opt/plcnext/logs/Output.log).

In the following is a positive start up of the app logged and described.

PxceTcs.Mqtt.GdsConnectorComponent    INFO  - Loaded configuration from file: /opt/plcnext/projects/MqttClient/mqtt_gds.settings.json  
PxceTcs.Mqtt.GdsConnectorComponent    INFO  - Loaded configuration schema.  

The configuration was loaded successfully, no schema violations were detected.

Note: Every schema violation (missing json separators or missing mandatory fields) will lead to an error at this position. The message indicates the error type.

PxceTcs.Mqtt.GdsConnectorComponent    INFO  - No reconnect port has been specified.  
PxceTcs.Mqtt.GdsConnectorComponent    INFO  - Created MQTT Client with ID: 56022  
PxceTcs.Mqtt.GdsConnectorComponent    INFO  - No MQTT SSL/TLS Options provided. Defaults will be used.  
PxceTcs.MqttClient.MqttClientManager  INFO  - Connecting to MQTT server  
PxceTcs.MqttClient.MqttClientManager  INFO  - Connected  
PxceTcs.Mqtt.GdsConnectorComponent    INFO  - Connected to MQTT Client 56022

After the configuration was loaded, generates the MQTT client a random client ID and tries to connect with the defined MQTT Broker.

Note: Connection or certification problems will lead to an error at this position.

PxceTcs.Mqtt.GdsConnectorComponent    INFO  - Subscribed to MQTT topic LoadTestBool  
PxceTcs.Mqtt.GdsConnectorComponent    INFO  - Subscribed to MQTT topic LoadTestBool1  
PxceTcs.Mqtt.GdsConnectorComponent    INFO  - SetupConfig(): Worker thread has been started. 

As soon as the connection is valid, the MQTT Client will start to publish and subscribe the configured topics. The cyclic update is performed with a worker thread (500ms). The app is now running.

Source code

This Function Extension uses two PLCnext Technology components. The source code for these components is available on Github:

Community contributions to these open-source projects are welcome.

How to get support

The MQTT Client app is supported in the forum of the PLCnext Community. Please raise an issue with a detailed error description and always provide a copy of the Output.log file.


Copyright © 2019 Phoenix Contact Electronics GmbH

All rights reserved. This program and the accompanying materials are made available under the terms of the MIT License which accompanies this distribution.


This code uses:

  1. JSON for Modern C++

    Copyright (c) 2013-2019 Niels Lohmann

    Licensed under the MIT License which accompanies this distribution.

    The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the MIT License (see above). Copyright © 2008-2009 Björn Hoehrmann bjoern@hoehrmann.de

    The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the MIT License (see above). Copyright © 2009 Florian Loitsch

  2. valijson

    Copyright (c) 2016, Tristan Penman

    Copyright (c) 2016, Akamai Technolgies, Inc.

    All rights reserved.

    Licensed under the Simplified BSD License which accompanies this distribution.