summaryrefslogtreecommitdiffstats
path: root/examples/opcua/waterpump/waterpump-qmlcpp/doc/waterpump-qmlcpp.qdoc
blob: 51f5e89239dcffda4fd7825163de306fd4395510 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/****************************************************************************
**
** Copyright (C) 2018 basysKom GmbH, info@basyskom.com
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \example waterpump/waterpump-qmlcpp
    \ingroup qtopcua-examples
    \title Using Qt OPC UA in a basic UI application
    \brief This example shows how to use Qt OPC UA to interact with an OPC UA
    server to build a QML based HMI for a simple machine.

    \section1 Introduction
    This example shows how to use Qt OPC UA to interact with an OPC UA
    server to build a QML based HMI for a simple machine.

    \section1 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:

    \table
        \header
            \li NodeId
            \li Function
        \row
            \li ns=2;s=Machine
            \li The folder containing the method and variable nodes for the machine
        \row
            \li ns=2;s=Machine.State
            \li The state of the machine
        \row
            \li ns=2;s=Machine.Tank1.PercentFilled
            \li The current fill status of the first tank
        \row
            \li ns=2;s=Machine.Tank2.PercentFilled
            \li The current fill status of the second tank
        \row
            \li ns=2;s=Machine.Tank2.TargetPercent
            \li The setpoint for pumping and flushing
        \row
            \li ns=2;s=Machine.Tank2.ValveState
            \li The state of the valve of the second tank
        \row
            \li ns=2;s=Machine.Designation
            \li A human readable designation of the machine for display purposes
        \row
            \li ns=2;s=Machine.Start
            \li Call this method to start the pump
        \row
            \li ns=2;s=Machine.Stop
            \li Call this method to stop the pump
        \row
            \li ns=2;s=Machine.FlushTank2
            \li Call this method to flush tank 2
    \endtable

    All methods return \l {QOpcUa::UaStatusCode} {Good} in case of success and
    \l {QOpcUa::UaStatusCode} {BadUserAccessDenied} if the operation is illegal
    (e. g. trying to start the pump if the first tank is empty).

    \section1 Used Features of \l QOpcUaClient
    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.

    \section1 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.

    \section2 Member Variables
    A pointer to \l QOpcUaClient is required for connection management. An
    additional pointer to a \l 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.

    \quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.h
    \dots
    \skipto m_client
    \printuntil m_machineDesignation;
    \codeline
    \dots

    For each value used in the HMI, a getter, a changed signal and a
    property are added to enable property bindings in QML

    \quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.h
    \dots
    \skipto Q_PROPERTY
    \printuntil QString message
    \dots

    \section2 Asynchronous Handlers

    The asynchronous API of Qt OPC UA requires signal handlers for all operations.

    Data change subscriptions report their updates using \l QOpcUaNode::attributeUpdated.
    A handler connected to this signal gets the new value as QVariant and can
    e. g. write that value to a variable or emit a signal with the new value.

    \quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
    \skipto void OpcUaMachineBackend::percentFilledTank1Updated
    \printuntil }

    A read operation emits the \l QOpcUaNode::attributeRead signal on completion.
    The client has to check the status code and then get the result from the node.

    \skipto void OpcUaMachineBackend::machineDesignationRead
    \printuntil }
    \printuntil }
    \printuntil }

    \section2 Interaction with the Server

    In the constructor, a QOpcUaProvider is created and the available backends are saved to provide a model for the backend selection dropdown menu.

    \quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
    \dots
    \skipto QOpcUaProvider provider
    \printuntil setBackends
    \dots

    Before attempting a connection, a QOpcUaClient with the selected backend is created. Its \l QOpcUaClient::stateChanged signal must be
    connected to the backend's clientStateHandler slot.

    \quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
    \skipto OpcUaMachineBackend::connectToEndpoint
    \printuntil m_client->connectToEndpoint
    \printuntil }

    clientStateHandler acts on QOpcUaClient being connected or disconnected.
    In case of a successful connection, the node member variables created before
    are filled with node objects.

    \dots
    \quotefromfile waterpump/waterpump-qmlcpp/opcuamachinebackend.cpp
    \skipto if (state == QOpcUaClient::ClientState::Connected) {
    \printuntil m_machineDesignationNode
    \dots

    After all node objects have been created, the data change handlers are
    connected to the node objects and monitoring is enabled.

    \dots
    \skipto Connect signal handlers
    \printuntil m_tank2ValveStateNode->enableMonitoring
    \dots

    The machine designation is not supposed to change and will be read once at
    startup.

    \dots
    \skipto Connect the handler for async reading
    \printuntil m_machineDesignationNode->readAttributes
    \codeline
    \dots

    A setter for the setpoint is added to the backend.

    \skipto machineWriteTank2TargetPercent
    \printuntil }

    For the methods, wrappers which call the OPC UA server method are created.

    \skipto startPump
    \printuntil }

    \section2 The HMI

    A backend instance is created and handed to the QML part as a context property
    named uaBackend.

    \dots
    \quotefromfile waterpump/waterpump-qmlcpp/main.cpp
    \skipto     OpcUaMachineBackend backend
    \printuntil setContextProperty
    \dots

    The properties, signals and Q_INVOKABLE methods of uaBackend can now be accessed by
    the QML code. For example, the button to flush the second tank is enabled
    only if the backend is connected to the server, the machine is idle and
    the tank level is above the setpoint. On click, the flushTank2() method
    is called on the server.

    \quotefromfile waterpump/waterpump-qmlcpp/Tank2Unit.qml
    \skipto     Button
    \printuntil }
    \printuntil }

    Signals from the backend can also be used directly in the QML code.

    \quotefromfile waterpump/waterpump-qmlcpp/Pump.qml
    \skipto Connections
    \printuntil }
    \printuntil }

    \section1 Usage
    The server is started automatically by the HMI application.
    After connecting to the server by clicking the \uicontrol Connect button,
    drag the slider to set a setpoint, then click \uicontrol Start to start pumping water
    from the first tank to the second tank. After setting a setpoint lower than
    the current value of the second tank, a click on \uicontrol Flush opens the valve.

    If there is no water left, click \uicontrol {Reset simulation} to refill the first tank.

    \image tankexample.jpg
*/