Low-level service calls¶
If you need full control over a request — fill in every optional field, override a default, or capture the raw response — every service the o6 client supports has a serviceX method that takes a pre-built request object and returns a pre-built response.
The high-level methods (client.read, client.write, client.call, client.browse, …) are thin wrappers over the same calls.
This page walks through the low-level basics:
- Build a request object.
- Call the corresponding
serviceXmethod. - Read fields off the response.
Info
This tutorials requires you to know how to create and connect a client and how to use the high-level API for read / write and call. We assume a server is running on localhost as described in example server in the tutorials intro.
Build a request object¶
Each service has a paired request type that lives in o6.ns.ns0.
The request has the same fields as the spec's request message — required fields set, optional fields left at their defaults:
from o6.ns.ns0.datatypes import ReadRequest, ReadValueId
req = ReadRequest()
req.nodesToRead = [ReadValueId("ns=1;i=1204")]
ReadValueId accepts a plain NodeId string directly in its constructor for the simple case of reading the Value attribute — you only need to build it up field-by-field (attributeId=, indexRange=, dataEncoding=) when you're after something other than Value. Request types themselves (ReadRequest, WriteRequest, …) take no constructor arguments — build one with Type() and set its fields by attribute, as above.
Call the corresponding serviceX method¶
The suffix of a serviceX method is the OPC UA service name.
Pass the request, get the response back:
from o6 import Client
with Client("opc.tcp://localhost:4840") as client:
response = client.serviceRead(req)
The complete list of serviceX methods on the client mirrors the OPC UA service sets:
- Discovery:
serviceFindServers,serviceFindServersOnNetwork,serviceGetEndpoints - Node management:
serviceAddNodes,serviceDeleteNodes,serviceAddReferences,serviceDeleteReferences - View:
serviceBrowse,serviceBrowseNext,serviceTranslateBrowsePathsToNodeIds,serviceRegisterNodes,serviceUnregisterNodes - Attribute:
serviceRead,serviceHistoryRead,serviceWrite,serviceHistoryUpdate - Method:
serviceCall
Every serviceX method returns a MaybeAwaitable to be readily used in both sync and async contexts — add await in async code:
Read fields off the response¶
The response object mirrors the spec's response message. Read the fields you care about the same way you read any Python attribute:
with Client("opc.tcp://localhost:4840") as client:
req = ReadRequest()
req.nodesToRead = [ReadValueId("ns=1;i=1204")] # Status.Setpoint
response = client.serviceRead(req)
# First check the service-level result code
print(response.responseHeader.serviceResult) # StatusCode.Good
# Then read the per-node results
result = response.results[0]
print(result.status) # StatusCode.Good
print(result.value) # e.g. 90.0
A non-Good responseHeader.serviceResult means the whole service call failed (e.g. the secure channel is in a bad state).
A non-Good per-node status means only that node failed.
The serviceX methods do not raise on either — they hand you the raw response and let you decide.
Tip
Start with the high-level API (client.read, client.write, client.call, …). Drop down to serviceX only when you've outgrown the wrapper — typically because you need a header field, an unusual parameter combination, or to debug a low-level status code.
What's next?¶
- Read / write value and Call a method — the high-level wrappers.
- The Client API reference — full surface of every
serviceXmethod.