Waterpump Example▲
Waterpump shows how to use Qt OPC UA to interact with an OPC UA server to build a QML-based HMI for a simple machine.
Building the Server▲
Before you can use the waterpump examples, you need to build the simulation server. The simulator server project resides next to the waterpump examples. You can open and build it in QtCreator or from the terminal as usual.
The Simulation▲
The OPC UA server included in this example runs a simulation of a machine containing two tanks, a water pump, and a valve. Water can be pumped from the first tank into the second tank and then be flushed from the second tank by opening the valve. Both operations have a user-configurable setpoint which controls how much water is pumped to or flushed from the second tank.
The following nodes exist on the server:
Function |
|
---|---|
ns=2;s=Machine |
The folder containing the method and variable nodes for the machine |
ns=2;s=Machine.State |
The state of the machine |
ns=2;s=Machine.Tank1.PercentFilled |
The current fill status of the first tank |
ns=2;s=Machine.Tank2.PercentFilled |
The current fill status of the second tank |
ns=2;s=Machine.Tank2.TargetPercent |
The setpoint for pumping and flushing |
ns=2;s=Machine.Tank2.ValveState |
The state of the valve of the second tank |
ns=2;s=Machine.Designation |
A human readable designation of the machine for display purposes |
ns=2;s=Machine.Start |
Call this method to start the pump |
ns=2;s=Machine.Stop |
Call this method to stop the pump |
ns=2;s=Machine.FlushTank2 |
Call this method to flush tank 2 |
All methods return Good in case of success and BadUserAccessDenied if the operation is illegal (for example, trying to start the pump if the first tank is empty).
Client Features▲
This example uses read, write, method calls, and data change subscriptions and shows how to set up handlers for the asynchronous operations offered by QOpcUaClient and QOpcUaNode.
Implementation▲
A backend class is used to handle the communication with the OPC UA server and expose the content of this server by means of properties and Q_INVOKABLE methods wrapping the OPC UA method calls.
Member Variables▲
A pointer to QOpcUaClient is required for connection management. An additional pointer to a QOpcUaNode object is needed for each OPC UA node the HMI interacts with. For the values of these nodes, member variables containing the last value reported by the server are added.
...
QScopedPointer&
lt;QOpcUaClient&
gt; m_client;
QScopedPointer&
lt;QOpcUaNode&
gt; m_machineStateNode;
QScopedPointer&
lt;QOpcUaNode&
gt; m_percentFilledTank1Node;
QScopedPointer&
lt;QOpcUaNode&
gt; m_percentFilledTank2Node;
QScopedPointer&
lt;QOpcUaNode&
gt; m_tank2TargetPercentNode;
QScopedPointer&
lt;QOpcUaNode&
gt; m_tank2ValveStateNode;
QScopedPointer&
lt;QOpcUaNode&
gt; m_machineNode;
QScopedPointer&
lt;QOpcUaNode&
gt; m_machineDesignationNode;
double
m_percentFilledTank1;
double
m_percentFilledTank2;
double
m_tank2TargetPercent;
bool
m_tank2ValveState;
MachineState m_machineState;
QString m_machineDesignation;
...
For each value used in the HMI, a getter, a changed signal, and a property are added to enable property bindings in QML
...
Q_PROPERTY(double
percentFilledTank1 READ percentFilledTank1 NOTIFY percentFilledTank1Changed)
Q_PROPERTY(double
percentFilledTank2 READ percentFilledTank2 NOTIFY percentFilledTank2Changed)
Q_PROPERTY(double
tank2TargetPercent READ tank2TargetPercent NOTIFY tank2TargetPercentChanged)
Q_PROPERTY(OpcUaMachineBackend::
MachineState machineState READ machineState NOTIFY machineStateChanged)
Q_PROPERTY(bool
tank2ValveState READ tank2