Skip to content

Configuration

Walks through the configuration surface of o6.Client. Every property the client cares about (endpoint URL, request timeout, session name, application identity, security settings, …) lives on the ClientConfig object returned by client.config and can be read and (in most cases) written through Python attribute access.

The key rule this example demonstrates: all writes to client.config must happen before the client is connected. The SDK raises RuntimeError if you try to mutate a field while the session is active.

This example talks to the same address space as the other high-level examples, served by S03_firststeps.py.

This example needs a running server

Start Server First Steps first:

python examples/server/S03_firststeps.py

The o6.Client constructor takes a small set of connect-time keyword arguments (endpoint URL, security mode, application URI, certificate paths, username and password). The rest of the configuration fields (request timeout, session timeout, secure channel lifetime, application description, …) can only be reached through client.config; they are not constructor arguments.

1. Inspect the Default Configuration

client.config exposes the client settings. The defaults below are what the SDK ships with. You will not be using most of them, but it's useful to see them in one place before you start changing any.

print("--- 1. Inspect the Default Configuration ---")
localhost = "localhost"
endpoint_url = EXAMPLE_ENDPOINT
print(f"Connecting to {endpoint_url} ...")

with o6.Client(endpoint_url) as client:
    cfg = client.config

    print(f"endpoint_url              = {cfg.endpointUrl!r}")
    print(f"timeout (ms)              = {cfg.timeout}")
    print(f"session_name              = {cfg.sessionName!r}")
    print(f"application_uri           = {cfg.applicationUri!r}")
    print(f"secure_channel_life_time  = {cfg.secureChannelLifeTime} ms")
    print(f"requested_session_timeout = {cfg.requestedSessionTimeout} ms")
    print(f"max_async_service_calls   = {cfg.maxAsyncServiceCalls}")
    print(f"no_session                = {cfg.noSession}")
    print(f"no_reconnect              = {cfg.noReconnect}")
    print(f"security_mode             = {cfg.securityMode}")
    print(f"security_policy           = {cfg.securityPolicy!r}")

2. Configure Before You Connect

Every field on ClientConfig is either connect-time (set once, baked into the SecureChannel and ActivateSession handshake), or runtime (read-only at runtime; can be inspected but not changed once connected).

The SDK enforces this: writing to a connect-time field while the client is connected raises RuntimeError. The block below demonstrates the failure mode so you can recognize it if you hit it.

print()
print("--- 2. Configure Before You Connect ---")
with o6.Client(endpoint_url) as client:
    cfg = client.config
    try:
        cfg.timeout = 1234
    except RuntimeError as e:
        print(f"Error: {e}")

3. Set Scalar Fields Before Connecting

The correct workflow is: construct the client, mutate client.config as you like, then enter the with block (or call connect() explicitly).

print()
print("--- 3. Set Scalar Fields Before Connecting ---")
client = o6.Client(endpoint_url)
client.config.timeout = 1234  # milliseconds
client.config.sessionName = "hmi-client-1"  # shown in the server's session list
client.config.secureChannelLifeTime = 300_000  # 5 minutes
client.config.maxAsyncServiceCalls = 128  # concurrent calls; 0 disables the limit

print(f"timeout                  = {client.config.timeout}")
print(f"session_name             = {client.config.sessionName!r}")
print(f"secure_channel_life_time = {client.config.secureChannelLifeTime}")
print(f"max_async_service_calls  = {client.config.maxAsyncServiceCalls}")

with client as c:
    cfg = c.config
    print(f"timeout (connected)      = {cfg.timeout}")

4. Set the Application Identity

When the client opens a session, the server is told who is connecting: an ApplicationDescription with the application's URI, a human-readable name, the application type (client, server, or both), and a product URI.

The ApplicationDescription class is on ns0.datatypes; the LocalizedText wrapper for the name field is on the o6 module. Both are simple Python classes: instantiate them, set the fields, then assign the result to client.config.applicationDescription. This must also happen before the client is connected.

print()
print("--- 4. Set the Application Identity ---")
client = o6.Client(endpoint_url)
cfg = client.config

ApplicationDescription = ns0.datatypes.ApplicationDescription
ApplicationType = ns0.datatypes.ApplicationType

desc = ApplicationDescription()
desc.applicationUri = "urn:example:o6:demo-client"
desc.applicationName = LocalizedText("o6 Demo Client")
desc.applicationType = ApplicationType.CLIENT
desc.productUri = "urn:example:o6"

cfg.applicationDescription = desc

print(f"application_uri  = {cfg.applicationDescription.applicationUri!r}")
print(f"application_name = {cfg.applicationDescription.applicationName!r}")
print(f"application_type = {cfg.applicationDescription.applicationType}")
print(f"product_uri      = {cfg.applicationDescription.productUri!r}")

with client as c:
    cfg = c.config
    print(f"application_description (connected) = {cfg.applicationDescription}")

5. Constructor and client.config

A small number of connect-time settings can be passed either to the o6.Client(...) constructor (application_uri, the security mode/policy, certificate paths, username/password) or written to client.config before connecting. Both routes end up in the same underlying ClientConfig object.

Everything else (timeout, session name, secure channel lifetime, the full ApplicationDescription, …) is only reachable through client.config. So these fields have to be defined before connecting.

The block below uses the constructor for application_uri and client.config for the read-only inspection, then enters the with block to verify the value and read a real variable.

print()
print("--- 5. Constructor and client.config ---")
with o6.Client(
    endpoint_url,
    applicationUri="urn:example:o6:demo-client",
) as client:
    cfg = client.config
    print(f"endpoint_url    = {cfg.endpointUrl!r}")
    print(f"application_uri = {cfg.applicationUri!r}")

    value = client.read("ns=1;i=1004")  # Plant / Counter
    print(f"Counter = {value}")

print()
print("=== Example completed ===")

Source Code

Download C04_configuration.py to run it locally.