Manager Lifecycle

The Manager class is the entry point for all interactions with WinCC OA. It manages the connection to the runtime system, the event loop, and graceful shutdown.

Creating a Manager

from etm.wccoa.manager import Manager

manager = Manager()

The constructor takes no arguments. Everything the manager needs — project, manager number, PMON index — is read from the command line the process was started with, exactly as in every other WinCC OA manager.

A process hosts exactly one WinCC OA manager identity, so Manager is a singleton: every further call of Manager() returns the same object. A module that needs the manager can therefore simply create it again instead of receiving it as a parameter.

Creating the instance does not connect to anything yet. The connection is established by start().

For application code, receiving the manager as a parameter is still the better choice. It keeps the import of etm.wccoa.manager out of the modules under test — see Writing Testable Code.

Manual Start and Stop

If the lifecycle cannot be expressed as a block, start() and stop() can be called directly. Use try / finally so that stop() also runs when the script fails.

manager = Manager()
manager.start()
try:
    value = manager.dp_get("ExampleDP_Arg1.")
finally:
    manager.stop()

stop() releases the singleton. API methods must not be called after stop().

A manager can be started only once per process. Calling start() again after stop(), also on a new Manager() instance, raises RuntimeError.

What start() and stop() Do

start() blocks until the connection to the Event and Data manager is established and then

  • adds the python/libs directory of every WinCC OA search-path level to sys.path, so that project and installation packages are importable; the order is the same as on the PYTHONPATH PMON sets: project, subprojects, installation, all behind the directory of the started script,
  • installs the log handler that forwards the Python logging records to WinCC OA (see Logging),
  • starts the internal event-loop thread that communicates with the runtime system,
  • creates the thread pool that delivers subscription callbacks,
  • registers the shutdown guards described in Signal Handling and Shutdown.

stop() reverses this in the opposite order and disconnects from the runtime system.

Configuration Options

The manager is not configured in code. It takes its configuration from the command line of the process, like every other WinCC OA manager.

Option Meaning
-proj <project> Project the manager connects to
-num <number> Manager number, unique among all scripting managers (CTRL, NodeJS, Python) of the project
-pmonIndex <index> Position in the manager list; set by PMON

Further standard WinCC OA manager options are accepted as well.

When the script runs as a manager of a project, these options come from the options field in the Console; PMON adds -PROJ and -pmonIndex and sets the environment variables the script needs. See Options Field.

When the script is started manually — during development or under a debugger — the options and the environment have to be provided by hand. See Running a Script Against a Local Project.

Threads

Three kinds of threads exist in a running Python manager.

Thread Created by Runs
Script thread and any thread you start yourself your script your code
Event-loop thread start() the communication with the runtime system
Callback pool threads start() the callbacks of your subscriptions

All API methods are thread-safe and may be called from any of your own threads without locking. Callbacks are always delivered on a pool thread and may call the API themselves — a dp_set inside a dp_connect callback is safe and does not block the runtime communication.

The event-loop thread is internal. Calling an API method on it raises RuntimeError instead of deadlocking.

Keeping the Script Running

The manager lives as long as the script runs. A script that only subscribes to values would leave the with block immediately, stop the manager and end the process, so no callback would ever arrive. Such a script blocks on wait():

with Manager() as manager:
    manager.dp_connect(on_change, ["ExampleDP_Arg1."])
    manager.wait()

wait() returns when the manager is stopped — by SIGTERM or SIGINT, or by stop() called from a callback or from another thread. Given a timeout it returns False if the time elapses while the manager is still running.

Signal Handling and Shutdown

PMON stops a manager with SIGTERM, which makes this the normal shutdown path in a project. The signal is handled by the WinCC OA SDK, the same way every C++ manager handles it, and is acted upon on the internal event-loop thread — a Python handler would need the main thread to run bytecode, which a blocking wait() prevents. wait() returns once the manager has been stopped and then raises SystemExit, so finally blocks and context managers of the script still run.

As a safety net, start() also registers an atexit handler. It stops the manager if the script ends without leaving the with block or calling stop(). It is a fallback, not a replacement for a proper lifecycle.