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
|
# BobinkQtOpcUa
A C++ library that wraps [Qt OPC UA](https://doc.qt.io/qt-6/qtopcua-index.html) into simple QML components for Qt Quick applications. Hide OPC UA complexity behind a clean, declarative API.
## Quick start
### Prerequisites
- CMake >= 3.16, Ninja
- Qt 6.10.2+ (with `qt-cmake` in PATH)
- OpenSSL development headers
### Build
```bash
git clone --recurse-submodules https://github.com/user/BobinkQtOpcUa.git
cd BobinkQtOpcUa
qt-cmake -S . -B build -G Ninja
qt-cmake --build build --parallel
```
The first configure automatically builds the bundled dependencies (open62541 and QtOpcUa) from git submodules under `deps/`. Subsequent builds skip this step.
### Run the demo
```bash
./build/bin/BobinkDemo
```
The demo app discovers local OPC UA servers, connects with configurable authentication and security, and lets you monitor and write to nodes.
## Usage
Import the `Bobink` QML module:
```qml
import Bobink
```
### Connect to a server
```qml
Connections {
target: Bobink
function onConnectedChanged() {
console.log("Connected:", Bobink.connected)
}
function onConnectionError(message) {
console.log("Error:", message)
}
function onCertificateTrustRequested(certInfo) {
// Show certInfo to user, then call:
Bobink.acceptCertificate() // or rejectCertificate()
}
}
Button {
text: "Connect"
onClicked: {
Bobink.serverUrl = "opc.tcp://localhost:4840"
Bobink.connectToServer()
}
}
```
`connectToServer()` discovers endpoints and auto-selects the most secure one. If that fails, use `connectDirect()` with explicit security settings:
```qml
Bobink.connectDirect(Bobink.Basic256Sha256, Bobink.SignAndEncrypt)
```
### Authentication
```qml
OpcUaAuth {
id: auth
mode: OpcUaAuth.Anonymous // or UserPass, Certificate
username: "user"
password: "pass"
}
// Set before connecting
Bobink.auth = auth
Bobink.connectToServer()
```
### Monitor and write nodes
```qml
OpcUaMonitoredNode {
id: tempNode
nodeId: "ns=2;s=Temperature"
monitored: true // creates an OPC UA monitored item
publishingInterval: 500 // ms
onValueChanged: console.log("Temperature:", value)
onWriteCompleted: (success, message) => console.log(message)
}
// Display live value
Text { text: "Temperature: " + tempNode.value }
// Write a new value
Button {
text: "Set to 25"
enabled: tempNode.writable
onClicked: tempNode.writeValue(25)
}
```
Type coercion is automatic -- QML values are converted to the node's OPC UA data type. For arrays, pass a comma-separated string: `writeValue("1, 2, 3")`.
Write to specific array elements with index range syntax:
```qml
tempNode.writeValueAtRange("42", "0") // first element
tempNode.writeValueAtRange("1, 2, 3", "0:2") // elements 0-2
```
### Node metadata
Each `OpcUaMonitoredNode` exposes an `info` property with metadata read once on setup:
```qml
Text { text: node.info.displayName }
Text { text: node.info.dataType }
Text { text: node.info.description }
// Also: nodeClass, valueRank, arrayDimensions, accessLevel,
// status, sourceTimestamp, serverTimestamp
```
### Server discovery
```qml
Component.onCompleted: {
Bobink.discoveryUrl = "opc.tcp://localhost:4840"
Bobink.startDiscovery()
}
ListView {
model: Bobink.servers
delegate: Text {
text: modelData.serverName
// Also available: modelData.applicationUri, modelData.discoveryUrls
}
}
```
### PKI
Client certificates are auto-detected from the default PKI directory (`<AppDataLocation>/pki`). To configure manually:
```qml
Bobink.pkiDir = "/path/to/pki"
Bobink.certFile = "/path/to/cert.der"
Bobink.keyFile = "/path/to/key.pem"
Bobink.applyPki()
```
## Use as a git submodule
BobinkQtOpcUa can be added to your project as a git submodule:
```bash
git submodule add https://github.com/user/BobinkQtOpcUa.git deps/bobink
git submodule update --init --recursive
```
```cmake
# CMakeLists.txt
add_subdirectory(deps/bobink)
# Link against the library and its QML plugin
target_link_libraries(YourApp PRIVATE BobinkQtOpcUaplugin)
# Set RPATH so the open62541 backend plugin loads at runtime
set(CMAKE_BUILD_RPATH "${OPEN62541_INSTALL_DIR}/lib"
"${QTOPCUA_INSTALL_DIR}/lib")
# Tell Qt where to find the OPC UA backend plugin
target_compile_definitions(YourApp PRIVATE
QTOPCUA_PLUGIN_PATH="${QTOPCUA_INSTALL_DIR}/plugins")
```
## Project structure
```
src/
OpcUaClient.h/.cpp Bobink singleton: connection, discovery, PKI
OpcUaMonitoredNode.h/.cpp Node monitoring, reading, writing
OpcUaAuth.h/.cpp Authentication configuration
demo/
Main.qml Connection UI demo
NodePage.qml Node interaction demo
deps/
open62541/ C OPC UA stack (submodule)
qtopcua/ Qt OPC UA module (submodule)
```
|